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();