1 | // |
2 | // Thread_STD_POSIX.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: Threading |
6 | // Module: Thread |
7 | // |
8 | // Copyright (c) 2004-2007, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Thread_STD.h" |
16 | #include "Poco/Thread.h" |
17 | #include "Poco/Exception.h" |
18 | #include <pthread.h> |
19 | #include <signal.h> |
20 | #if defined(__sun) && defined(__SVR4) |
21 | #if !defined(__EXTENSIONS__) |
22 | #define __EXTENSIONS__ |
23 | #endif |
24 | #endif |
25 | #if POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_ANDROID || POCO_OS == POCO_OS_MAC_OS_X || POCO_OS == POCO_OS_QNX |
26 | #include <time.h> |
27 | #include <unistd.h> |
28 | #endif |
29 | #if POCO_OS == POCO_OS_MAC_OS_X |
30 | #include <mach/mach.h> |
31 | #include <mach/task.h> |
32 | #include <mach/thread_policy.h> |
33 | #endif |
34 | #if POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_ANDROID |
35 | #include <sys/syscall.h> |
36 | #endif |
37 | #include <cstring> |
38 | |
39 | |
40 | namespace Poco { |
41 | |
42 | |
43 | int mapPrio(int prio, int policy) |
44 | { |
45 | int pmin = ThreadImpl::getMinOSPriorityImpl(policy); |
46 | int pmax = ThreadImpl::getMaxOSPriorityImpl(policy); |
47 | |
48 | switch (prio) |
49 | { |
50 | case ThreadImpl::PRIO_LOWEST_IMPL: |
51 | return pmin; |
52 | case ThreadImpl::PRIO_LOW_IMPL: |
53 | return pmin + (pmax - pmin) / 4; |
54 | case ThreadImpl::PRIO_NORMAL_IMPL: |
55 | return pmin + (pmax - pmin) / 2; |
56 | case ThreadImpl::PRIO_HIGH_IMPL: |
57 | return pmin + 3 * (pmax - pmin) / 4; |
58 | case ThreadImpl::PRIO_HIGHEST_IMPL: |
59 | return pmax; |
60 | default: |
61 | poco_bugcheck_msg("invalid thread priority" ); |
62 | } |
63 | return -1; // just to satisfy compiler - we'll never get here anyway |
64 | } |
65 | |
66 | |
67 | int reverseMapPrio(int prio, int policy) |
68 | { |
69 | if (policy == SCHED_OTHER) |
70 | { |
71 | int pmin = ThreadImpl::getMinOSPriorityImpl(policy); |
72 | int pmax = ThreadImpl::getMaxOSPriorityImpl(policy); |
73 | int normal = pmin + (pmax - pmin) / 2; |
74 | if (prio == pmax) |
75 | return ThreadImpl::PRIO_HIGHEST_IMPL; |
76 | if (prio > normal) |
77 | return ThreadImpl::PRIO_HIGH_IMPL; |
78 | else if (prio == normal) |
79 | return ThreadImpl::PRIO_NORMAL_IMPL; |
80 | else if (prio > pmin) |
81 | return ThreadImpl::PRIO_LOW_IMPL; |
82 | else |
83 | return ThreadImpl::PRIO_LOWEST_IMPL; |
84 | } |
85 | else return ThreadImpl::PRIO_HIGHEST_IMPL; |
86 | } |
87 | |
88 | |
89 | void ThreadImpl::setPriorityImpl(int prio) |
90 | { |
91 | if (prio != _pData->prio) |
92 | { |
93 | _pData->prio = prio; |
94 | _pData->policy = SCHED_OTHER; |
95 | if (isRunningImpl()) |
96 | { |
97 | struct sched_param par; |
98 | par.sched_priority = mapPrio(_pData->prio, SCHED_OTHER); |
99 | if (pthread_setschedparam(_pData->thread->native_handle(), SCHED_OTHER, &par)) |
100 | throw SystemException("cannot set thread priority" ); |
101 | } |
102 | } |
103 | } |
104 | |
105 | |
106 | void ThreadImpl::setOSPriorityImpl(int prio, int policy) |
107 | { |
108 | if (prio != _pData->osPrio || policy != _pData->policy) |
109 | { |
110 | if (_pData->pRunnableTarget) |
111 | { |
112 | struct sched_param par; |
113 | par.sched_priority = (policy == SCHED_OTHER) ? 0 : prio; |
114 | if (pthread_setschedparam(_pData->thread->native_handle(), policy, &par)) |
115 | throw SystemException("cannot set thread priority" ); |
116 | } |
117 | _pData->prio = reverseMapPrio(prio, policy); |
118 | _pData->osPrio = prio; |
119 | _pData->policy = policy; |
120 | } |
121 | } |
122 | |
123 | |
124 | int ThreadImpl::getMinOSPriorityImpl(int policy) |
125 | { |
126 | #if defined(POCO_THREAD_PRIORITY_MIN) |
127 | return POCO_THREAD_PRIORITY_MIN; |
128 | #elif defined(__digital__) |
129 | return PRI_OTHER_MIN; |
130 | #else |
131 | return sched_get_priority_min(policy); |
132 | #endif |
133 | } |
134 | |
135 | |
136 | int ThreadImpl::getMaxOSPriorityImpl(int policy) |
137 | { |
138 | #if defined(POCO_THREAD_PRIORITY_MAX) |
139 | return POCO_THREAD_PRIORITY_MAX; |
140 | #elif defined(__digital__) |
141 | return PRI_OTHER_MAX; |
142 | #else |
143 | return sched_get_priority_max(policy); |
144 | #endif |
145 | } |
146 | |
147 | |
148 | void ThreadImpl::setStackSizeImpl(int size) |
149 | { |
150 | _pData->stackSize = size; |
151 | // not supported |
152 | } |
153 | |
154 | |
155 | void ThreadImpl::setAffinityImpl(int cpu) |
156 | { |
157 | #if defined (POCO_OS_FAMILY_UNIX) && POCO_OS != POCO_OS_MAC_OS_X && POCO_OS != POCO_OS_FREE_BSD |
158 | #ifdef HAVE_PTHREAD_SETAFFINITY_NP |
159 | cpu_set_t cpuset; |
160 | CPU_ZERO(&cpuset); |
161 | CPU_SET(cpu, &cpuset); |
162 | #ifdef HAVE_THREE_PARAM_SCHED_SETAFFINITY |
163 | if (pthread_setaffinity_np(_pData->thread->native_handle(), sizeof(cpuset), &cpuset) != 0) |
164 | throw SystemException("Failed to set affinity" ); |
165 | #else |
166 | if (pthread_setaffinity_np(_pData->thread->native_handle(), &cpuset) != 0) |
167 | throw SystemException("Failed to set affinity" ); |
168 | #endif |
169 | #endif |
170 | #endif // defined unix & !defined mac os x |
171 | |
172 | #if POCO_OS == POCO_OS_MAC_OS_X |
173 | kern_return_t ret; |
174 | thread_affinity_policy policy; |
175 | policy.affinity_tag = cpu; |
176 | |
177 | ret = thread_policy_set(pthread_mach_thread_np(_pData->thread->native_handle()), |
178 | THREAD_AFFINITY_POLICY, |
179 | (thread_policy_t)&policy, |
180 | THREAD_AFFINITY_POLICY_COUNT); |
181 | if (ret != KERN_SUCCESS) |
182 | { |
183 | throw SystemException("Failed to set affinity" ); |
184 | } |
185 | #endif |
186 | yieldImpl(); |
187 | _pData->cpu = cpu; |
188 | } |
189 | |
190 | |
191 | int ThreadImpl::getAffinityImpl() const |
192 | { |
193 | int cpuSet = -1; |
194 | #if defined (POCO_OS_FAMILY_UNIX) && POCO_OS != POCO_OS_MAC_OS_X && POCO_OS != POCO_OS_FREE_BSD |
195 | #ifdef HAVE_PTHREAD_SETAFFINITY_NP |
196 | cpu_set_t cpuset; |
197 | CPU_ZERO(&cpuset); |
198 | #ifdef HAVE_THREE_PARAM_SCHED_SETAFFINITY |
199 | if (pthread_getaffinity_np(_pData->thread->native_handle(), sizeof(cpuset), &cpuset) != 0) |
200 | throw SystemException("Failed to get affinity" , errno); |
201 | #else |
202 | if (pthread_getaffinity_np(_pData->thread->native_handle(), &cpuset) != 0) |
203 | throw SystemException("Failed to get affinity" , errno); |
204 | #endif |
205 | int cpuCount = Environment::processorCount(); |
206 | for (int i = 0; i < cpuCount; i++) |
207 | { |
208 | if (CPU_ISSET(i, &cpuset)) |
209 | { |
210 | cpuSet = i; |
211 | break; |
212 | } |
213 | } |
214 | #endif |
215 | #endif // defined unix & !defined mac os x |
216 | |
217 | #if POCO_OS == POCO_OS_MAC_OS_X |
218 | kern_return_t ret; |
219 | thread_affinity_policy policy; |
220 | mach_msg_type_number_t count = THREAD_AFFINITY_POLICY_COUNT; |
221 | boolean_t get_default = false; |
222 | ret = thread_policy_get(pthread_mach_thread_np(_pData->thread->native_handle()), |
223 | THREAD_AFFINITY_POLICY, |
224 | (thread_policy_t)&policy, |
225 | &count, |
226 | &get_default); |
227 | if (ret != KERN_SUCCESS) |
228 | { |
229 | throw SystemException("Failed to get affinity" , errno); |
230 | } |
231 | cpuSet = policy.affinity_tag; |
232 | int cpuCount = Environment::processorCount(); |
233 | if (cpuSet >= cpuCount) |
234 | cpuSet = -1; |
235 | |
236 | #endif |
237 | return cpuSet; |
238 | } |
239 | |
240 | long ThreadImpl::currentOsTidImpl() |
241 | { |
242 | #if POCO_OS == POCO_OS_LINUX |
243 | return syscall(SYS_gettid); |
244 | #elif POCO_OS == POCO_OS_MAC_OS_X |
245 | return pthread_mach_thread_np(pthread_self()); |
246 | #else |
247 | return pthread_self(); |
248 | #endif |
249 | } |
250 | |
251 | |
252 | } // namespace Poco |
253 | |