diff --git a/Foundation/include/Poco/Config.h b/Foundation/include/Poco/Config.h index 8de4e610b..571e2f504 100644 --- a/Foundation/include/Poco/Config.h +++ b/Foundation/include/Poco/Config.h @@ -52,6 +52,11 @@ #define POCO_THREAD_STACK_SIZE 0 #endif +// Defined to desired max thread name length +#ifndef POCO_MAX_THREAD_NAME_LEN +#define POCO_MAX_THREAD_NAME_LEN 15 +#endif + // Define to override system-provided // minimum thread priority value on POSIX diff --git a/Foundation/include/Poco/Thread.h b/Foundation/include/Poco/Thread.h index f29d7b46f..891773f85 100644 --- a/Foundation/include/Poco/Thread.h +++ b/Foundation/include/Poco/Thread.h @@ -95,6 +95,7 @@ public: void setName(const std::string& name); /// Sets the name of the thread. + /// Note that it only take effect before start method invoked. void setPriority(Priority prio); /// Sets the thread's priority. @@ -275,10 +276,8 @@ private: Thread& operator = (const Thread&); int _id; - std::string _name; ThreadLocalStorage* _pTLS; Event _event; - mutable FastMutex _mutex; friend class ThreadLocalStorage; friend class PooledThread; @@ -302,17 +301,13 @@ inline int Thread::id() const inline std::string Thread::name() const { - FastMutex::ScopedLock lock(_mutex); - - return _name; + return getNameImpl(); } inline std::string Thread::getName() const { - FastMutex::ScopedLock lock(_mutex); - - return _name; + return getNameImpl(); } diff --git a/Foundation/include/Poco/Thread_POSIX.h b/Foundation/include/Poco/Thread_POSIX.h index b46351009..cd3b1e62d 100644 --- a/Foundation/include/Poco/Thread_POSIX.h +++ b/Foundation/include/Poco/Thread_POSIX.h @@ -36,10 +36,8 @@ #include #endif - namespace Poco { - class Foundation_API ThreadImpl { public: @@ -64,6 +62,12 @@ public: ~ThreadImpl(); TIDImpl tidImpl() const; + void setNameImpl(const std::string& threadName); + std::string getNameImpl() const; + std::string getOSThreadNameImpl(); + /// Returns the thread's name, expressed as an operating system + /// specific name value. Return empty string if thread is not running. + /// For test used only. void setPriorityImpl(int prio); int getPriorityImpl() const; void setOSPriorityImpl(int prio, int policy = SCHED_OTHER); @@ -141,6 +145,7 @@ private: std::size_t stackSize; bool started; bool joined; + std::string name; mutable FastMutex mutex; }; diff --git a/Foundation/include/Poco/Thread_VX.h b/Foundation/include/Poco/Thread_VX.h index 506c5ab67..d44c869bd 100644 --- a/Foundation/include/Poco/Thread_VX.h +++ b/Foundation/include/Poco/Thread_VX.h @@ -70,6 +70,12 @@ public: ~ThreadImpl(); TIDImpl tidImpl() const; + void setNameImpl(const std::string& threadName); + std::string getNameImpl() const; + std::string getOSThreadNameImpl(); + /// Returns the thread's name, expressed as an operating system + /// specific name value. Return empty string if thread is not running. + /// For test used only. void setPriorityImpl(int prio); int getPriorityImpl() const; void setOSPriorityImpl(int prio, int policy = 0); @@ -111,11 +117,12 @@ protected: Runnable* pRunnableTarget; AutoPtr pCallbackTarget; - int task; - int prio; - int osPrio; - Event done; - int stackSize; + int task; + int prio; + int osPrio; + Event done; + int stackSize; + std::string name; }; private: diff --git a/Foundation/include/Poco/Thread_WIN32.h b/Foundation/include/Poco/Thread_WIN32.h index 2d44a20bc..4967d60a6 100644 --- a/Foundation/include/Poco/Thread_WIN32.h +++ b/Foundation/include/Poco/Thread_WIN32.h @@ -57,6 +57,12 @@ public: ~ThreadImpl(); TIDImpl tidImpl() const; + void setNameImpl(const std::string& threadName); + std::string getNameImpl() const; + std::string getOSThreadNameImpl(); + /// Returns the thread's name, expressed as an operating system + /// specific name value. Return empty string if thread is not running. + /// For test used only. void setPriorityImpl(int prio); int getPriorityImpl() const; void setOSPriorityImpl(int prio, int policy = 0); @@ -116,6 +122,7 @@ private: DWORD _threadId; int _prio; int _stackSize; + std::string _name; static CurrentThreadHolder _currentThreadHolder; }; diff --git a/Foundation/include/Poco/Thread_WINCE.h b/Foundation/include/Poco/Thread_WINCE.h index 47e9f18e8..e4996c92d 100644 --- a/Foundation/include/Poco/Thread_WINCE.h +++ b/Foundation/include/Poco/Thread_WINCE.h @@ -57,6 +57,12 @@ public: ~ThreadImpl(); TIDImpl tidImpl() const; + void setNameImpl(const std::string& threadName); + std::string getNameImpl() const; + std::string getOSThreadNameImpl(); + /// Returns the thread's name, expressed as an operating system + /// specific name value. Return empty string if thread is not running. + /// For test used only. void setPriorityImpl(int prio); int getPriorityImpl() const; void setOSPriorityImpl(int prio, int policy = 0); @@ -112,6 +118,7 @@ private: DWORD _threadId; int _prio; int _stackSize; + std::string _name; static CurrentThreadHolder _currentThreadHolder; }; diff --git a/Foundation/src/Thread.cpp b/Foundation/src/Thread.cpp index 0ebcba967..de5cb3adb 100644 --- a/Foundation/src/Thread.cpp +++ b/Foundation/src/Thread.cpp @@ -90,19 +90,19 @@ private: Thread::Thread(): _id(uniqueId()), - _name(makeName()), _pTLS(0), _event(true) { + setNameImpl(makeName()); } Thread::Thread(const std::string& name): _id(uniqueId()), - _name(name), _pTLS(0), _event(true) { + setNameImpl(name); } @@ -210,9 +210,7 @@ int Thread::uniqueId() void Thread::setName(const std::string& name) { - FastMutex::ScopedLock lock(_mutex); - - _name = name; + setNameImpl(name); } diff --git a/Foundation/src/Thread_POSIX.cpp b/Foundation/src/Thread_POSIX.cpp index ceab76e82..189c52e23 100644 --- a/Foundation/src/Thread_POSIX.cpp +++ b/Foundation/src/Thread_POSIX.cpp @@ -62,21 +62,25 @@ namespace #endif -namespace { -void setThreadName(pthread_t thread, const std::string& threadName) +namespace { -#if (POCO_OS == POCO_OS_MAC_OS_X) - pthread_setname_np(threadName.c_str()); // __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2) -#else - if (pthread_setname_np(thread, threadName.c_str()) == ERANGE && threadName.size() > 15) + void setThreadName(const std::string& threadName) { - std::string truncName(threadName, 0, 7); - truncName.append("~"); - truncName.append(threadName, threadName.size() - 7, 7); - pthread_setname_np(thread, truncName.c_str()); - } +#if (POCO_OS == POCO_OS_MAC_OS_X) + if (pthread_setname_np(threadName.c_str())) +#else + if (pthread_setname_np(pthread_self(), threadName.c_str())) #endif -} + throw Poco::SystemException("cannot get thread name"); + } + + std::string getThreadName() + { + char name[POCO_MAX_THREAD_NAME_LEN + 1]{'\0'}; + if (pthread_getname_np(pthread_self(), name, POCO_MAX_THREAD_NAME_LEN + 1)) + throw Poco::SystemException("cannot get thread name"); + return name; + } } @@ -100,6 +104,44 @@ ThreadImpl::~ThreadImpl() } } +void ThreadImpl::setNameImpl(const std::string& threadName) +{ + std::string realName = threadName; +#if (POCO_OS == POCO_OS_MAC_OS_X) + if (threadName.size() > POCO_MAX_THREAD_NAME_LEN) + { + int half = (POCO_MAX_THREAD_NAME_LEN - 1) / 2; +#else + if (threadName.size() > std::min(POCO_MAX_THREAD_NAME_LEN, 15)) + { + int half = (std::min(POCO_MAX_THREAD_NAME_LEN, 15) - 1) / 2; +#endif + std::string truncName(threadName, 0, half); + truncName.append("~"); + truncName.append(threadName, threadName.size() - half); + realName = truncName; + } + + ScopedLock lock(_pData->mutex); + if (realName != _pData->name) + { + _pData->name = realName; + } +} + + +std::string ThreadImpl::getNameImpl() const +{ + ScopedLock lock(_pData->mutex); + return _pData->name; +} + + +std::string ThreadImpl::getOSThreadNameImpl() +{ + return isRunningImpl() ? getThreadName() : ""; +} + void ThreadImpl::setPriorityImpl(int prio) { @@ -350,9 +392,14 @@ void* ThreadImpl::runnableEntry(void* pThread) pthread_sigmask(SIG_BLOCK, &sset, 0); #endif - ThreadImpl* pThreadImpl = reinterpret_cast(pThread); - setThreadName(pThreadImpl->_pData->thread, reinterpret_cast(pThread)->getName()); + auto* pThreadImpl = reinterpret_cast(pThread); AutoPtr pData = pThreadImpl->_pData; + + { + FastMutex::ScopedLock lock(pData->mutex); + setThreadName(pData->name); + } + try { pData->pRunnableTarget->run(); diff --git a/Foundation/src/Thread_VX.cpp b/Foundation/src/Thread_VX.cpp index 9cefd4312..acb64a63c 100644 --- a/Foundation/src/Thread_VX.cpp +++ b/Foundation/src/Thread_VX.cpp @@ -37,6 +37,38 @@ ThreadImpl::~ThreadImpl() } +void ThreadImpl::setNameImpl(const std::string& threadName) +{ + std::string realName = threadName; + if (threadName.size() > POCO_MAX_THREAD_NAME_LEN) + { + int half = (POCO_MAX_THREAD_NAME_LEN - 1) / 2; + std::string truncName(threadName, 0, half); + truncName.append("~"); + truncName.append(threadName, threadName.size() - half); + realName = truncName; + } + + if (realName != _pData->name) + { + _pData->name = realName; + } +} + + +std::string ThreadImpl::getNameImpl() const +{ + return _pData->name; +} + + +std::string ThreadImpl::getOSThreadNameImpl() +{ + // return fake thread name; + return isRunningImpl() ? _pData->name : ""; +} + + void ThreadImpl::setPriorityImpl(int prio) { if (prio != _pData->prio) @@ -141,7 +173,7 @@ ThreadImpl* ThreadImpl::currentImpl() ThreadImpl::TIDImpl ThreadImpl::currentTidImpl() { - return taskIdSelf(); + return taskIdSelf(); } long ThreadImpl::currentOsTidImpl() @@ -181,6 +213,7 @@ void ThreadImpl::runnableEntry(void* pThread, int, int, int, int, int, int, int, _pCurrent = reinterpret_cast(pThread); AutoPtr pData = _pCurrent->_pData; + try { pData->pRunnableTarget->run(); diff --git a/Foundation/src/Thread_WIN32.cpp b/Foundation/src/Thread_WIN32.cpp index 15bb65667..87f8bb219 100644 --- a/Foundation/src/Thread_WIN32.cpp +++ b/Foundation/src/Thread_WIN32.cpp @@ -18,9 +18,6 @@ #include -#if defined(POCO_WIN32_DEBUGGER_THREAD_NAMES) - - namespace { /// See @@ -38,29 +35,26 @@ namespace DWORD dwFlags; // Reserved for future use, must be zero. } THREADNAME_INFO; #pragma pack(pop) - - void setThreadName(DWORD dwThreadID, const char* threadName) + + void setThreadName(DWORD dwThreadID, const std::string& threadName) { - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = threadName; - info.dwThreadID = dwThreadID; - info.dwFlags = 0; + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = threadName.c_str(); + info.dwThreadID = dwThreadID; + info.dwFlags = 0; - __try - { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } - __except (EXCEPTION_CONTINUE_EXECUTION) - { - } + __try + { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except (EXCEPTION_CONTINUE_EXECUTION) + { + } } } -#endif - - namespace Poco { @@ -82,6 +76,37 @@ ThreadImpl::~ThreadImpl() } +void ThreadImpl::setNameImpl(const std::string& threadName) +{ + std::string realName = threadName; + if (threadName.size() > POCO_MAX_THREAD_NAME_LEN) + { + int half = (POCO_MAX_THREAD_NAME_LEN - 1) / 2; + std::string truncName(threadName, 0, half); + truncName.append("~"); + truncName.append(threadName, threadName.size() - half); + realName = truncName; + } + + if (realName != _name) + { + _name = realName; + } +} + + +std::string ThreadImpl::getNameImpl() const +{ + return _name; +} + +std::string ThreadImpl::getOSThreadNameImpl() +{ + // return fake thread name + return isRunningImpl() ? _name : ""; +} + + void ThreadImpl::setPriorityImpl(int prio) { if (prio != _prio) @@ -200,10 +225,9 @@ DWORD WINAPI ThreadImpl::runnableEntry(LPVOID pThread) unsigned __stdcall ThreadImpl::runnableEntry(void* pThread) #endif { - _currentThreadHolder.set(reinterpret_cast(pThread)); -#if defined(POCO_WIN32_DEBUGGER_THREAD_NAMES) - setThreadName(-1, reinterpret_cast(pThread)->getName().c_str()); -#endif + auto * pThreadImpl = reinterpret_cast(pThread); + _currentThreadHolder.set(pThreadImpl); + setThreadName(-1, pThreadImpl->_name); try { reinterpret_cast(pThread)->_pRunnableTarget->run(); diff --git a/Foundation/src/Thread_WINCE.cpp b/Foundation/src/Thread_WINCE.cpp index 310f89419..84544bbdf 100644 --- a/Foundation/src/Thread_WINCE.cpp +++ b/Foundation/src/Thread_WINCE.cpp @@ -16,7 +16,6 @@ #include "Poco/Exception.h" #include "Poco/ErrorHandler.h" - namespace Poco { @@ -38,6 +37,35 @@ ThreadImpl::~ThreadImpl() if (_thread) CloseHandle(_thread); } +void ThreadImpl::setNameImpl(const std::string& threadName) +{ + std::string realName = threadName; + if (threadName.size() > POCO_MAX_THREAD_NAME_LEN) + { + int half = (POCO_MAX_THREAD_NAME_LEN - 1) / 2; + std::string truncName(threadName, 0, half); + truncName.append("~"); + truncName.append(threadName, threadName.size() - half); + realName = truncName; + } + + if (realName != _name) + { + _name = realName; + } +} + + +std::string ThreadImpl::getNameImpl() const +{ + return _name; +} + +std::string ThreadImpl::getOSThreadNameImpl() +{ + // return fake thread name; + return isRunningImpl() ? _name : ""; +} void ThreadImpl::setPriorityImpl(int prio) { diff --git a/Foundation/testsuite/src/ThreadTest.cpp b/Foundation/testsuite/src/ThreadTest.cpp index e1346fe90..65f981d42 100644 --- a/Foundation/testsuite/src/ThreadTest.cpp +++ b/Foundation/testsuite/src/ThreadTest.cpp @@ -41,7 +41,11 @@ public: { Thread* pThread = Thread::current(); if (pThread) + { _threadName = pThread->name(); + auto *pThreadImpl = reinterpret_cast(pThread); + _osThreadName = pThreadImpl->getOSThreadNameImpl(); + } _ran = true; _event.wait(); } @@ -56,6 +60,11 @@ public: return _threadName; } + const std::string& osThreadName() const + { + return _osThreadName; + } + void notify() { _event.set(); @@ -71,6 +80,7 @@ public: private: bool _ran; std::string _threadName; + std::string _osThreadName; Event _event; }; @@ -168,6 +178,7 @@ void ThreadTest::testThread() assertTrue (!thread.isRunning()); assertTrue (r.ran()); assertTrue (!r.threadName().empty()); + assertTrue (!r.osThreadName().empty()); } @@ -180,6 +191,19 @@ void ThreadTest::testNamedThread() thread.join(); assertTrue (r.ran()); assertTrue (r.threadName() == "MyThread"); + assertTrue (r.osThreadName() == r.threadName()); + + // name len > POCO_MAX_THREAD_NAME_LEN + Thread thread2("0123456789aaaaaaaaaa9876543210"); + MyRunnable r2; + thread2.start(r2); + r2.notify(); + thread2.join(); + assertTrue (r2.ran()); + assertTrue (r2.osThreadName() == r2.threadName()); + assertTrue (r2.threadName().length() <= POCO_MAX_THREAD_NAME_LEN); + assertTrue (std::string(r2.threadName(), 0, 7) == "0123456"); + assertTrue (std::string(r2.threadName(), r2.threadName().size() - 7) == "6543210"); }