/src/poco/Foundation/include/Poco/Thread_POSIX.h
Line | Count | Source |
1 | | // |
2 | | // Thread_POSIX.h |
3 | | // |
4 | | // Library: Foundation |
5 | | // Package: Threading |
6 | | // Module: Thread |
7 | | // |
8 | | // Definition of the ThreadImpl class for POSIX Threads. |
9 | | // |
10 | | // Copyright (c) 2004-2007, Applied Informatics Software Engineering GmbH. |
11 | | // and Contributors. |
12 | | // |
13 | | // SPDX-License-Identifier: BSL-1.0 |
14 | | // |
15 | | |
16 | | |
17 | | #ifndef Foundation_Thread_POSIX_INCLUDED |
18 | | #define Foundation_Thread_POSIX_INCLUDED |
19 | | |
20 | | |
21 | | #include "Poco/Foundation.h" |
22 | | #include "Poco/Mutex.h" |
23 | | #include "Poco/Runnable.h" |
24 | | #include "Poco/SignalHandler.h" |
25 | | #include "Poco/Event.h" |
26 | | #include "Poco/RefCountedObject.h" |
27 | | #include "Poco/AutoPtr.h" |
28 | | #include "Poco/SharedPtr.h" |
29 | | #include <pthread.h> |
30 | | // must be limits.h (not <climits>) for PTHREAD_STACK_MIN on Solaris |
31 | | #include <limits.h> |
32 | | #if !defined(POCO_NO_SYS_SELECT_H) |
33 | | #include <sys/select.h> |
34 | | #endif |
35 | | #if defined(POCO_VXWORKS) |
36 | | #include <cstring> |
37 | | #endif |
38 | | |
39 | | namespace Poco { |
40 | | |
41 | | class Foundation_API ThreadImpl |
42 | | { |
43 | | public: |
44 | | using TIDImpl = pthread_t; |
45 | | using Callable = void (*)(void *); |
46 | | |
47 | | enum Priority |
48 | | { |
49 | | PRIO_LOWEST_IMPL, |
50 | | PRIO_LOW_IMPL, |
51 | | PRIO_NORMAL_IMPL, |
52 | | PRIO_HIGH_IMPL, |
53 | | PRIO_HIGHEST_IMPL |
54 | | }; |
55 | | |
56 | | enum Policy |
57 | | { |
58 | | POLICY_DEFAULT_IMPL = SCHED_OTHER |
59 | | }; |
60 | | |
61 | | ThreadImpl(); |
62 | | ~ThreadImpl(); |
63 | | |
64 | | [[nodiscard]] TIDImpl tidImpl() const; |
65 | | void setNameImpl(const std::string& threadName); |
66 | | [[nodiscard]] std::string getNameImpl() const; |
67 | | #ifndef POCO_NO_THREADNAME |
68 | | [[nodiscard]] std::string getOSThreadNameImpl(); |
69 | | /// Returns the thread's name, expressed as an operating system |
70 | | /// specific name value. Return empty string if thread is not running. |
71 | | /// For test used only. |
72 | | #endif |
73 | | void setPriorityImpl(int prio); |
74 | | [[nodiscard]] int getPriorityImpl() const; |
75 | | void setOSPriorityImpl(int prio, int policy = SCHED_OTHER); |
76 | | [[nodiscard]] int getOSPriorityImpl() const; |
77 | | [[nodiscard]] static int getMinOSPriorityImpl(int policy); |
78 | | [[nodiscard]] static int getMaxOSPriorityImpl(int policy); |
79 | | void setStackSizeImpl(int size); |
80 | | [[nodiscard]] int getStackSizeImpl() const; |
81 | | void setSignalMaskImpl(uint32_t sigMask); |
82 | | void startImpl(SharedPtr<Runnable> pTarget); |
83 | | void joinImpl(); |
84 | | bool joinImpl(long milliseconds); |
85 | | [[nodiscard]] bool isRunningImpl() const; |
86 | | static void yieldImpl(); |
87 | | [[nodiscard]] static ThreadImpl* currentImpl(); |
88 | | [[nodiscard]] static TIDImpl currentTidImpl(); |
89 | | [[nodiscard]] static long currentOsTidImpl(); |
90 | | #ifndef POCO_NO_THREADNAME |
91 | | static void setCurrentNameImpl(const std::string& name); |
92 | | [[nodiscard]] static std::string getCurrentNameImpl(); |
93 | | #endif |
94 | | bool setAffinityImpl(int coreID); |
95 | | [[nodiscard]] int getAffinityImpl() const; |
96 | | |
97 | | protected: |
98 | | [[nodiscard]] static void* runnableEntry(void* pThread); |
99 | | [[nodiscard]] static int mapPrio(int prio, int policy = SCHED_OTHER); |
100 | | [[nodiscard]] static int reverseMapPrio(int osPrio, int policy = SCHED_OTHER); |
101 | | |
102 | | private: |
103 | | class CurrentThreadHolder |
104 | | { |
105 | | public: |
106 | | CurrentThreadHolder() |
107 | 0 | { |
108 | 0 | if (pthread_key_create(&_key, nullptr)) |
109 | 0 | throw SystemException("cannot allocate thread context key"); |
110 | 0 | } |
111 | | ~CurrentThreadHolder() |
112 | 0 | { |
113 | 0 | pthread_key_delete(_key); |
114 | 0 | } |
115 | | [[nodiscard]] ThreadImpl* get() const |
116 | 0 | { |
117 | 0 | return reinterpret_cast<ThreadImpl*>(pthread_getspecific(_key)); |
118 | 0 | } |
119 | | void set(ThreadImpl* pThread) |
120 | 0 | { |
121 | 0 | pthread_setspecific(_key, pThread); |
122 | 0 | } |
123 | | |
124 | | private: |
125 | | pthread_key_t _key; |
126 | | }; |
127 | | |
128 | | struct ThreadData: public RefCountedObject |
129 | | { |
130 | | ThreadData(): |
131 | | thread{}, |
132 | | prio(PRIO_NORMAL_IMPL), |
133 | | osPrio(), |
134 | | policy(SCHED_OTHER), |
135 | | done(Event::EVENT_MANUALRESET), |
136 | | stackSize(POCO_THREAD_STACK_SIZE), |
137 | | started(false), |
138 | | joined(false) |
139 | 0 | { |
140 | 0 | #if defined(POCO_VXWORKS) |
141 | 0 | // This workaround is for VxWorks 5.x where |
142 | 0 | // pthread_init() won't properly initialize the thread. |
143 | 0 | std::memset(&thread, 0, sizeof(thread)); |
144 | 0 | #endif |
145 | 0 | } |
146 | | |
147 | | SharedPtr<Runnable> pRunnableTarget; |
148 | | pthread_t thread; |
149 | | int prio; |
150 | | int osPrio; |
151 | | int policy; |
152 | | Event done; |
153 | | std::size_t stackSize; |
154 | | std::atomic<bool> started; |
155 | | std::atomic<bool> joined; |
156 | | std::string name; |
157 | | int affinity; |
158 | | mutable FastMutex mutex; |
159 | | }; |
160 | | |
161 | | AutoPtr<ThreadData> _pData; |
162 | | static CurrentThreadHolder _currentThreadHolder; |
163 | | |
164 | | #if defined(POCO_OS_FAMILY_UNIX) && !defined(POCO_VXWORKS) |
165 | | SignalHandler::JumpBufferVec _jumpBufferVec; |
166 | | friend class SignalHandler; |
167 | | #endif |
168 | | }; |
169 | | |
170 | | |
171 | | // |
172 | | // inlines |
173 | | // |
174 | | inline int ThreadImpl::getPriorityImpl() const |
175 | 0 | { |
176 | 0 | return _pData->prio; |
177 | 0 | } |
178 | | |
179 | | |
180 | | inline int ThreadImpl::getOSPriorityImpl() const |
181 | 0 | { |
182 | 0 | return _pData->osPrio; |
183 | 0 | } |
184 | | |
185 | | |
186 | | inline bool ThreadImpl::isRunningImpl() const |
187 | 0 | { |
188 | 0 | FastMutex::ScopedLock l(_pData->mutex); |
189 | 0 | return !_pData->pRunnableTarget.isNull(); |
190 | 0 | } |
191 | | |
192 | | |
193 | | inline void ThreadImpl::yieldImpl() |
194 | 0 | { |
195 | 0 | sched_yield(); |
196 | 0 | } |
197 | | |
198 | | |
199 | | inline int ThreadImpl::getStackSizeImpl() const |
200 | 0 | { |
201 | 0 | return static_cast<int>(_pData->stackSize); |
202 | 0 | } |
203 | | |
204 | | |
205 | | inline ThreadImpl::TIDImpl ThreadImpl::tidImpl() const |
206 | 0 | { |
207 | 0 | return _pData->thread; |
208 | 0 | } |
209 | | |
210 | | |
211 | | } // namespace Poco |
212 | | |
213 | | |
214 | | #endif // Foundation_Thread_POSIX_INCLUDED |