diff --git a/Foundation/include/Poco/Config.h b/Foundation/include/Poco/Config.h index e44f4e40d..c9c0445a2 100644 --- a/Foundation/include/Poco/Config.h +++ b/Foundation/include/Poco/Config.h @@ -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/Runnable.h b/Foundation/include/Poco/Runnable.h index 891ff179f..17d7d9c9c 100644 --- a/Foundation/include/Poco/Runnable.h +++ b/Foundation/include/Poco/Runnable.h @@ -51,7 +51,7 @@ class Foundation_API Runnable /// must be implemented by classes that provide /// an entry point for a thread. { -public: +public: Runnable(); virtual ~Runnable(); diff --git a/Foundation/include/Poco/Thread.h b/Foundation/include/Poco/Thread.h index 82836408f..87afbc7b2 100644 --- a/Foundation/include/Poco/Thread.h +++ b/Foundation/include/Poco/Thread.h @@ -127,13 +127,13 @@ public: /// Returns the maximum operating system-specific priority value, /// which can be passed to setOSPriority(). - void setStackSize(std::size_t size); + 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. - std::size_t getStackSize() const; + int getStackSize() const; /// Returns the thread's stack size in bytes. /// If the default stack size is used, 0 is returned. @@ -272,13 +272,13 @@ inline int Thread::getMaxOSPriority() } -inline void Thread::setStackSize(std::size_t size) +inline void Thread::setStackSize(int size) { setStackSizeImpl(size); } -inline std::size_t Thread::getStackSize() const +inline int Thread::getStackSize() const { return getStackSizeImpl(); } diff --git a/Foundation/include/Poco/ThreadPool.h b/Foundation/include/Poco/ThreadPool.h index 522e67ca6..99d7fbf82 100644 --- a/Foundation/include/Poco/ThreadPool.h +++ b/Foundation/include/Poco/ThreadPool.h @@ -89,6 +89,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 +166,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 d72bdc1fd..8403031df 100644 --- a/Foundation/include/Poco/Thread_POSIX.h +++ b/Foundation/include/Poco/Thread_POSIX.h @@ -89,8 +89,8 @@ public: int getOSPriorityImpl() const; static int getMinOSPriorityImpl(); static int getMaxOSPriorityImpl(); - void setStackSizeImpl(std::size_t size); - std::size_t getStackSizeImpl() const; + void setStackSizeImpl(int size); + int getStackSizeImpl() const; void startImpl(Runnable& target); void startImpl(Callback target, void* pData = 0); @@ -116,7 +116,7 @@ private: thread(0), prio(PRIO_NORMAL_IMPL), done(false), - stackSize(0) + stackSize(POCO_THREAD_STACK_SIZE) { } @@ -186,13 +186,7 @@ inline void ThreadImpl::yieldImpl() } -inline void ThreadImpl::setStackSizeImpl(std::size_t size) -{ - _pData->stackSize = size; -} - - -inline std::size_t ThreadImpl::getStackSizeImpl() const +inline int ThreadImpl::getStackSizeImpl() const { return _pData->stackSize; } diff --git a/Foundation/include/Poco/Thread_WIN32.h b/Foundation/include/Poco/Thread_WIN32.h index 414cb1487..1d931cb72 100644 --- a/Foundation/include/Poco/Thread_WIN32.h +++ b/Foundation/include/Poco/Thread_WIN32.h @@ -87,8 +87,8 @@ public: int getOSPriorityImpl() const; static int getMinOSPriorityImpl(); static int getMaxOSPriorityImpl(); - void setStackSizeImpl(std::size_t size); - std::size_t getStackSizeImpl() const; + void setStackSizeImpl(int size); + int getStackSizeImpl() const; void startImpl(Runnable& target); void startImpl(Callback target, void* pData = 0); @@ -120,7 +120,7 @@ private: CallbackData _callbackTarget; HANDLE _thread; int _prio; - std::size_t _stackSize; + int _stackSize; static DWORD _currentKey; }; @@ -165,13 +165,13 @@ inline void ThreadImpl::yieldImpl() } -inline void ThreadImpl::setStackSizeImpl(std::size_t size) +inline void ThreadImpl::setStackSizeImpl(int size) { _stackSize = size; } -inline std::size_t ThreadImpl::getStackSizeImpl() const +inline int ThreadImpl::getStackSizeImpl() const { return _stackSize; } diff --git a/Foundation/src/ThreadPool.cpp b/Foundation/src/ThreadPool.cpp index 7ceb44510..0e5243e50 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); } @@ -255,7 +257,8 @@ ThreadPool::ThreadPool(const std::string& name, int minCapacity, int maxCapacity _maxCapacity(maxCapacity), _idleTime(idleTime), _serial(0), - _age(0) + _age(0), + _stackSize(0) { poco_assert (minCapacity >= 1 && maxCapacity >= minCapacity && idleTime > 0); @@ -452,7 +455,7 @@ PooledThread* ThreadPool::createThread() { std::ostringstream name; name << _name << "[#" << ++_serial << "]"; - return new PooledThread(name.str()); + return new PooledThread(name.str(), _stackSize); } @@ -474,6 +477,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 94e6cf600..8b4694853 100644 --- a/Foundation/src/Thread_POSIX.cpp +++ b/Foundation/src/Thread_POSIX.cpp @@ -144,15 +144,28 @@ int ThreadImpl::getMaxOSPriorityImpl() } +void ThreadImpl::setStackSizeImpl(int size) +{ + if (size !=0 && size < PTHREAD_STACK_MIN) + size = PTHREAD_STACK_MIN; + + _pData->stackSize = size; +} + + void ThreadImpl::startImpl(Runnable& target) { - if (_pData->pRunnableTarget) throw SystemException("thread already running"); + if (_pData->pRunnableTarget) + 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 != pthread_attr_setstacksize(&attributes, _pData->stackSize)) + throw SystemException("cannot set thread stack size"); + } _pData->pRunnableTarget = ⌖ if (pthread_create(&_pData->thread, &attributes, runnableEntry, this)) @@ -180,7 +193,10 @@ void ThreadImpl::startImpl(Callback target, void* pData) pthread_attr_init(&attributes); if (_pData->stackSize != 0) - pthread_attr_setstacksize(&attributes, _pData->stackSize); + { + 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; diff --git a/Foundation/src/Thread_WIN32.cpp b/Foundation/src/Thread_WIN32.cpp index caaa4f79d..b6aa597e1 100644 --- a/Foundation/src/Thread_WIN32.cpp +++ b/Foundation/src/Thread_WIN32.cpp @@ -50,7 +50,7 @@ ThreadImpl::ThreadImpl(): _pRunnableTarget(0), _thread(0), _prio(PRIO_NORMAL_IMPL), - _stackSize(0) + _stackSize(POCO_THREAD_STACK_SIZE) { if (_currentKey == TLS_OUT_OF_INDEXES) { diff --git a/Foundation/testsuite/src/ThreadPoolTest.cpp b/Foundation/testsuite/src/ThreadPoolTest.cpp index cc1baf7ce..f6e749807 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 b25a041e0..1fac39049 100644 --- a/Foundation/testsuite/src/ThreadTest.cpp +++ b/Foundation/testsuite/src/ThreadTest.cpp @@ -263,17 +263,24 @@ void ThreadTest::testThreadFunction() void ThreadTest::testThreadStackSize() { + int stackSize = 50000000; + Thread thread; assert (0 == thread.getStackSize()); - thread.setStackSize(50000000); - assert (50000000 == thread.getStackSize()); + thread.setStackSize(stackSize); + assert (stackSize == thread.getStackSize()); int tmp = MyRunnable::_staticVar; thread.start(freeFunc, &tmp); thread.join(); assert (tmp * 2 == MyRunnable::_staticVar); - thread.setStackSize(1); - assert (1 == thread.getStackSize()); + stackSize = 1; + thread.setStackSize(stackSize); +#ifdef POCO_OS_FAMILY_UNIX + assert (PTHREAD_STACK_MIN == thread.getStackSize()); +#else + assert (stackSize == thread.getStackSize()); +#endif tmp = MyRunnable::_staticVar; thread.start(freeFunc, &tmp); thread.join();