Thread_POSIX.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. //
  2. // Thread_POSIX.cpp
  3. //
  4. // $Id: //poco/1.4/Foundation/src/Thread_POSIX.cpp#5 $
  5. //
  6. // Library: Foundation
  7. // Package: Threading
  8. // Module: Thread
  9. //
  10. // Copyright (c) 2004-2007, Applied Informatics Software Engineering GmbH.
  11. // and Contributors.
  12. //
  13. // SPDX-License-Identifier: BSL-1.0
  14. //
  15. #include "Poco/Thread_POSIX.h"
  16. #include "Poco/Thread.h"
  17. #include "Poco/Exception.h"
  18. #include "Poco/ErrorHandler.h"
  19. #include "Poco/Timespan.h"
  20. #include "Poco/Timestamp.h"
  21. #include <signal.h>
  22. #if defined(__sun) && defined(__SVR4)
  23. # if !defined(__EXTENSIONS__)
  24. # define __EXTENSIONS__
  25. # endif
  26. #endif
  27. #if POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_MAC_OS_X || POCO_OS == POCO_OS_QNX
  28. # include <time.h>
  29. #endif
  30. //
  31. // Block SIGPIPE in main thread.
  32. //
  33. #if defined(POCO_OS_FAMILY_UNIX) && !defined(POCO_VXWORKS)
  34. namespace
  35. {
  36. class SignalBlocker
  37. {
  38. public:
  39. SignalBlocker()
  40. {
  41. sigset_t sset;
  42. sigemptyset(&sset);
  43. sigaddset(&sset, SIGPIPE);
  44. pthread_sigmask(SIG_BLOCK, &sset, 0);
  45. }
  46. ~SignalBlocker()
  47. {
  48. }
  49. };
  50. static SignalBlocker signalBlocker;
  51. }
  52. #endif
  53. #if defined(POCO_POSIX_DEBUGGER_THREAD_NAMES)
  54. namespace
  55. {
  56. void setThreadName(pthread_t thread, const char* threadName)
  57. {
  58. # if (POCO_OS == POCO_OS_MAC_OS_X)
  59. pthread_setname_np(threadName); // __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2)
  60. # else
  61. pthread_setname_np(thread, threadName);
  62. # endif
  63. }
  64. }
  65. #endif
  66. namespace Poco {
  67. ThreadImpl::CurrentThreadHolder ThreadImpl::_currentThreadHolder;
  68. ThreadImpl::ThreadImpl():
  69. _pData(new ThreadData)
  70. {
  71. }
  72. ThreadImpl::~ThreadImpl()
  73. {
  74. if (_pData->started && !_pData->joined)
  75. {
  76. pthread_detach(_pData->thread);
  77. }
  78. }
  79. void ThreadImpl::setPriorityImpl(int prio)
  80. {
  81. if (prio != _pData->prio)
  82. {
  83. _pData->prio = prio;
  84. _pData->policy = SCHED_OTHER;
  85. if (isRunningImpl())
  86. {
  87. struct sched_param par; struct MyStruct
  88. {
  89. };
  90. par.sched_priority = mapPrio(_pData->prio, SCHED_OTHER);
  91. if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par))
  92. throw SystemException("cannot set thread priority");
  93. }
  94. }
  95. }
  96. void ThreadImpl::setOSPriorityImpl(int prio, int policy)
  97. {
  98. if (prio != _pData->osPrio || policy != _pData->policy)
  99. {
  100. if (_pData->pRunnableTarget)
  101. {
  102. struct sched_param par;
  103. par.sched_priority = prio;
  104. if (pthread_setschedparam(_pData->thread, policy, &par))
  105. throw SystemException("cannot set thread priority");
  106. }
  107. _pData->prio = reverseMapPrio(prio, policy);
  108. _pData->osPrio = prio;
  109. _pData->policy = policy;
  110. }
  111. }
  112. int ThreadImpl::getMinOSPriorityImpl(int policy)
  113. {
  114. #if defined(POCO_THREAD_PRIORITY_MIN)
  115. return POCO_THREAD_PRIORITY_MIN;
  116. #elif defined(__VMS) || defined(__digital__)
  117. return PRI_OTHER_MIN;
  118. #else
  119. return sched_get_priority_min(policy);
  120. #endif
  121. }
  122. int ThreadImpl::getMaxOSPriorityImpl(int policy)
  123. {
  124. #if defined(POCO_THREAD_PRIORITY_MAX)
  125. return POCO_THREAD_PRIORITY_MAX;
  126. #elif defined(__VMS) || defined(__digital__)
  127. return PRI_OTHER_MAX;
  128. #else
  129. return sched_get_priority_max(policy);
  130. #endif
  131. }
  132. void ThreadImpl::setStackSizeImpl(int size)
  133. {
  134. #ifndef PTHREAD_STACK_MIN
  135. _pData->stackSize = 0;
  136. #else
  137. if (size != 0)
  138. {
  139. #if defined(POCO_OS_FAMILY_BSD)
  140. // we must round up to a multiple of the memory page size
  141. const int STACK_PAGE_SIZE = 4096;
  142. size = ((size + STACK_PAGE_SIZE - 1)/STACK_PAGE_SIZE)*STACK_PAGE_SIZE;
  143. #endif
  144. #if !defined(POCO_ANDROID)
  145. if (size < PTHREAD_STACK_MIN)
  146. size = PTHREAD_STACK_MIN;
  147. #endif
  148. }
  149. _pData->stackSize = size;
  150. #endif
  151. }
  152. void ThreadImpl::startImpl(SharedPtr<Runnable> pTarget)
  153. {
  154. if (_pData->pRunnableTarget)
  155. throw SystemException("thread already running");
  156. pthread_attr_t attributes;
  157. pthread_attr_init(&attributes);
  158. if (_pData->stackSize != 0)
  159. {
  160. if (0 != pthread_attr_setstacksize(&attributes, _pData->stackSize))
  161. {
  162. pthread_attr_destroy(&attributes);
  163. throw SystemException("cannot set thread stack size");
  164. }
  165. }
  166. _pData->pRunnableTarget = pTarget;
  167. if (pthread_create(&_pData->thread, &attributes, runnableEntry, this))
  168. {
  169. _pData->pRunnableTarget = 0;
  170. pthread_attr_destroy(&attributes);
  171. throw SystemException("cannot start thread");
  172. }
  173. _pData->started = true;
  174. pthread_attr_destroy(&attributes);
  175. if (_pData->policy == SCHED_OTHER)
  176. {
  177. if (_pData->prio != PRIO_NORMAL_IMPL)
  178. {
  179. struct sched_param par;
  180. par.sched_priority = mapPrio(_pData->prio, SCHED_OTHER);
  181. if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par))
  182. throw SystemException("cannot set thread priority");
  183. }
  184. }
  185. else
  186. {
  187. struct sched_param par;
  188. par.sched_priority = _pData->osPrio;
  189. if (pthread_setschedparam(_pData->thread, _pData->policy, &par))
  190. throw SystemException("cannot set thread priority");
  191. }
  192. }
  193. void ThreadImpl::joinImpl()
  194. {
  195. if (!_pData->started) return;
  196. _pData->done.wait();
  197. void* result;
  198. if (pthread_join(_pData->thread, &result))
  199. throw SystemException("cannot join thread");
  200. _pData->joined = true;
  201. }
  202. bool ThreadImpl::joinImpl(long milliseconds)
  203. {
  204. if (_pData->started && _pData->done.tryWait(milliseconds))
  205. {
  206. void* result;
  207. if (pthread_join(_pData->thread, &result))
  208. throw SystemException("cannot join thread");
  209. _pData->joined = true;
  210. return true;
  211. }
  212. else if (_pData->started) return false;
  213. else return true;
  214. }
  215. ThreadImpl* ThreadImpl::currentImpl()
  216. {
  217. return _currentThreadHolder.get();
  218. }
  219. ThreadImpl::TIDImpl ThreadImpl::currentTidImpl()
  220. {
  221. return pthread_self();
  222. }
  223. void ThreadImpl::sleepImpl(long milliseconds)
  224. {
  225. #if defined(__VMS) || defined(__digital__)
  226. // This is specific to DECThreads
  227. struct timespec interval;
  228. interval.tv_sec = milliseconds / 1000;
  229. interval.tv_nsec = (milliseconds % 1000)*1000000;
  230. pthread_delay_np(&interval);
  231. #elif POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_MAC_OS_X || POCO_OS == POCO_OS_QNX || POCO_OS == POCO_OS_VXWORKS
  232. Poco::Timespan remainingTime(1000*Poco::Timespan::TimeDiff(milliseconds));
  233. int rc;
  234. do
  235. {
  236. struct timespec ts;
  237. ts.tv_sec = (long) remainingTime.totalSeconds();
  238. ts.tv_nsec = (long) remainingTime.useconds()*1000;
  239. Poco::Timestamp start;
  240. rc = ::nanosleep(&ts, 0);
  241. if (rc < 0 && errno == EINTR)
  242. {
  243. Poco::Timestamp end;
  244. Poco::Timespan waited = start.elapsed();
  245. if (waited < remainingTime)
  246. remainingTime -= waited;
  247. else
  248. remainingTime = 0;
  249. }
  250. }
  251. while (remainingTime > 0 && rc < 0 && errno == EINTR);
  252. if (rc < 0 && remainingTime > 0) throw Poco::SystemException("Thread::sleep(): nanosleep() failed");
  253. #else
  254. Poco::Timespan remainingTime(1000*Poco::Timespan::TimeDiff(milliseconds));
  255. int rc;
  256. do
  257. {
  258. struct timeval tv;
  259. tv.tv_sec = (long) remainingTime.totalSeconds();
  260. tv.tv_usec = (long) remainingTime.useconds();
  261. Poco::Timestamp start;
  262. rc = ::select(0, NULL, NULL, NULL, &tv);
  263. if (rc < 0 && errno == EINTR)
  264. {
  265. Poco::Timestamp end;
  266. Poco::Timespan waited = start.elapsed();
  267. if (waited < remainingTime)
  268. remainingTime -= waited;
  269. else
  270. remainingTime = 0;
  271. }
  272. }
  273. while (remainingTime > 0 && rc < 0 && errno == EINTR);
  274. if (rc < 0 && remainingTime > 0) throw Poco::SystemException("Thread::sleep(): select() failed");
  275. #endif
  276. }
  277. void* ThreadImpl::runnableEntry(void* pThread)
  278. {
  279. _currentThreadHolder.set(reinterpret_cast<ThreadImpl*>(pThread));
  280. #if defined(POCO_OS_FAMILY_UNIX)
  281. sigset_t sset;
  282. sigemptyset(&sset);
  283. sigaddset(&sset, SIGQUIT);
  284. sigaddset(&sset, SIGTERM);
  285. sigaddset(&sset, SIGPIPE);
  286. pthread_sigmask(SIG_BLOCK, &sset, 0);
  287. #endif
  288. ThreadImpl* pThreadImpl = reinterpret_cast<ThreadImpl*>(pThread);
  289. #if defined(POCO_POSIX_DEBUGGER_THREAD_NAMES)
  290. setThreadName(pThreadImpl->_pData->thread, reinterpret_cast<Thread*>(pThread)->getName().c_str());
  291. #endif
  292. AutoPtr<ThreadData> pData = pThreadImpl->_pData;
  293. try
  294. {
  295. pData->pRunnableTarget->run();
  296. }
  297. catch (Exception& exc)
  298. {
  299. ErrorHandler::handle(exc);
  300. }
  301. catch (std::exception& exc)
  302. {
  303. ErrorHandler::handle(exc);
  304. }
  305. catch (...)
  306. {
  307. ErrorHandler::handle();
  308. }
  309. pData->pRunnableTarget = 0;
  310. pData->done.set();
  311. return 0;
  312. }
  313. int ThreadImpl::mapPrio(int prio, int policy)
  314. {
  315. int pmin = getMinOSPriorityImpl(policy);
  316. int pmax = getMaxOSPriorityImpl(policy);
  317. switch (prio)
  318. {
  319. case PRIO_LOWEST_IMPL:
  320. return pmin;
  321. case PRIO_LOW_IMPL:
  322. return pmin + (pmax - pmin)/4;
  323. case PRIO_NORMAL_IMPL:
  324. return pmin + (pmax - pmin)/2;
  325. case PRIO_HIGH_IMPL:
  326. return pmin + 3*(pmax - pmin)/4;
  327. case PRIO_HIGHEST_IMPL:
  328. return pmax;
  329. default:
  330. poco_bugcheck_msg("invalid thread priority");
  331. }
  332. return -1; // just to satisfy compiler - we'll never get here anyway
  333. }
  334. int ThreadImpl::reverseMapPrio(int prio, int policy)
  335. {
  336. if (policy == SCHED_OTHER)
  337. {
  338. int pmin = getMinOSPriorityImpl(policy);
  339. int pmax = getMaxOSPriorityImpl(policy);
  340. int normal = pmin + (pmax - pmin)/2;
  341. if (prio == pmax)
  342. return PRIO_HIGHEST_IMPL;
  343. if (prio > normal)
  344. return PRIO_HIGH_IMPL;
  345. else if (prio == normal)
  346. return PRIO_NORMAL_IMPL;
  347. else if (prio > pmin)
  348. return PRIO_LOW_IMPL;
  349. else
  350. return PRIO_LOWEST_IMPL;
  351. }
  352. else return PRIO_HIGHEST_IMPL;
  353. }
  354. } // namespace Poco