diff --git a/CHANGELOG b/CHANGELOG index d58478770..85b88a65b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -29,6 +29,7 @@ Release 1.5.2 (2013-03-??) - redefined DefaultHandler as typedef to ParseHandler - fixed GH #127: Eliminate -Wshadow warnings - SocketAddress small object optimization +- fixed GH #79: Poco::Thread leak on Linux Release 1.5.1 (2013-01-11) ========================== diff --git a/Foundation/include/Poco/Thread_POSIX.h b/Foundation/include/Poco/Thread_POSIX.h index d24b5808a..db30b73b6 100644 --- a/Foundation/include/Poco/Thread_POSIX.h +++ b/Foundation/include/Poco/Thread_POSIX.h @@ -155,7 +155,8 @@ private: prio(PRIO_NORMAL_IMPL), policy(SCHED_OTHER), done(false), - stackSize(POCO_THREAD_STACK_SIZE) + stackSize(POCO_THREAD_STACK_SIZE), + joined(false) { #if defined(POCO_VXWORKS) // This workaround is for VxWorks 5.x where @@ -172,6 +173,7 @@ private: int policy; Event done; std::size_t stackSize; + bool joined; }; AutoPtr _pData; diff --git a/Foundation/src/Thread_POSIX.cpp b/Foundation/src/Thread_POSIX.cpp index e39b7a7d0..78248ed6a 100644 --- a/Foundation/src/Thread_POSIX.cpp +++ b/Foundation/src/Thread_POSIX.cpp @@ -51,7 +51,6 @@ # include #endif - // // Block SIGPIPE in main thread. // @@ -114,8 +113,10 @@ ThreadImpl::ThreadImpl(): ThreadImpl::~ThreadImpl() { - if (isRunningImpl()) + if (!_pData->joined) + { pthread_detach(_pData->thread); + } } @@ -269,9 +270,11 @@ void ThreadImpl::startImpl(Callable target, void* pData) { _pData->pCallbackTarget->callback = 0; _pData->pCallbackTarget->pData = 0; + pthread_attr_destroy(&attributes); throw SystemException("cannot start thread"); } - + pthread_attr_destroy(&attributes); + if (_pData->policy == SCHED_OTHER) { if (_pData->prio != PRIO_NORMAL_IMPL) @@ -297,7 +300,8 @@ void ThreadImpl::joinImpl() _pData->done.wait(); void* result; if (pthread_join(_pData->thread, &result)) - throw SystemException("cannot join thread"); + throw SystemException("cannot join thread"); + _pData->joined = true; } @@ -460,7 +464,6 @@ void* ThreadImpl::callableEntry(void* pThread) pData->pCallbackTarget->callback = 0; pData->pCallbackTarget->pData = 0; - pData->done.set(); return 0; } diff --git a/Foundation/testsuite/src/ThreadTest.cpp b/Foundation/testsuite/src/ThreadTest.cpp index acf740ed4..1877d0b93 100644 --- a/Foundation/testsuite/src/ThreadTest.cpp +++ b/Foundation/testsuite/src/ThreadTest.cpp @@ -112,6 +112,28 @@ void freeFunc(void* pData) } +class NonJoinRunnable : public Runnable +{ +public: + NonJoinRunnable() : _finished(false) + { + } + + void run() + { + _finished = true; + } + + bool finished() const + { + return _finished; + } + +private: + bool _finished; +}; + + ThreadTest::ThreadTest(const std::string& name): CppUnit::TestCase(name) { } @@ -226,6 +248,22 @@ void ThreadTest::testJoin() } +void ThreadTest::testNotJoin() +{ + Thread thread; + NonJoinRunnable r; + thread.start(r); + + while (!r.finished()) + { + Thread::sleep(10); + } + + Thread::sleep(100); + assert (!thread.isRunning()); +} + + void ThreadTest::testThreadTarget() { ThreadTarget te(&MyRunnable::staticFunc); @@ -335,6 +373,7 @@ CppUnit::Test* ThreadTest::suite() CppUnit_addTest(pSuite, ThreadTest, testCurrent); CppUnit_addTest(pSuite, ThreadTest, testThreads); CppUnit_addTest(pSuite, ThreadTest, testJoin); + CppUnit_addTest(pSuite, ThreadTest, testNotJoin); CppUnit_addTest(pSuite, ThreadTest, testThreadTarget); CppUnit_addTest(pSuite, ThreadTest, testThreadFunction); CppUnit_addTest(pSuite, ThreadTest, testThreadStackSize); diff --git a/Foundation/testsuite/src/ThreadTest.h b/Foundation/testsuite/src/ThreadTest.h index b4c98219f..843b2c33e 100644 --- a/Foundation/testsuite/src/ThreadTest.h +++ b/Foundation/testsuite/src/ThreadTest.h @@ -51,6 +51,7 @@ public: void testCurrent(); void testThreads(); void testJoin(); + void testNotJoin(); void testThreadTarget(); void testThreadFunction(); void testThreadStackSize();