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_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 |
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 | struct MyStruct |
99 | { |
100 | |
101 | }; |
102 | par.sched_priority = mapPrio(_pData->prio, SCHED_OTHER); |
103 | if (pthread_setschedparam(_pData->thread->native_handle(), SCHED_OTHER, &par)) |
104 | throw SystemException("cannot set thread priority" ); |
105 | } |
106 | } |
107 | } |
108 | |
109 | |
110 | void ThreadImpl::setOSPriorityImpl(int prio, int policy) |
111 | { |
112 | if (prio != _pData->osPrio || policy != _pData->policy) |
113 | { |
114 | if (_pData->pRunnableTarget) |
115 | { |
116 | struct sched_param par; |
117 | par.sched_priority = prio; |
118 | if (pthread_setschedparam(_pData->thread->native_handle(), policy, &par)) |
119 | throw SystemException("cannot set thread priority" ); |
120 | } |
121 | _pData->prio = reverseMapPrio(prio, policy); |
122 | _pData->osPrio = prio; |
123 | _pData->policy = policy; |
124 | } |
125 | } |
126 | |
127 | |
128 | int ThreadImpl::getMinOSPriorityImpl(int policy) |
129 | { |
130 | #if defined(POCO_THREAD_PRIORITY_MIN) |
131 | return POCO_THREAD_PRIORITY_MIN; |
132 | #elif defined(__VMS) || defined(__digital__) |
133 | return PRI_OTHER_MIN; |
134 | #else |
135 | return sched_get_priority_min(policy); |
136 | #endif |
137 | } |
138 | |
139 | |
140 | int ThreadImpl::getMaxOSPriorityImpl(int policy) |
141 | { |
142 | #if defined(POCO_THREAD_PRIORITY_MAX) |
143 | return POCO_THREAD_PRIORITY_MAX; |
144 | #elif defined(__VMS) || defined(__digital__) |
145 | return PRI_OTHER_MAX; |
146 | #else |
147 | return sched_get_priority_max(policy); |
148 | #endif |
149 | } |
150 | |
151 | |
152 | void ThreadImpl::setStackSizeImpl(int size) |
153 | { |
154 | _pData->stackSize = size; |
155 | // not supported |
156 | } |
157 | |
158 | |
159 | void ThreadImpl::setAffinityImpl(int cpu) |
160 | { |
161 | #if defined (POCO_OS_FAMILY_UNIX) && POCO_OS != POCO_OS_MAC_OS_X && POCO_OS != POCO_OS_FREE_BSD |
162 | #ifdef HAVE_PTHREAD_SETAFFINITY_NP |
163 | cpu_set_t cpuset; |
164 | CPU_ZERO(&cpuset); |
165 | CPU_SET(cpu, &cpuset); |
166 | #ifdef HAVE_THREE_PARAM_SCHED_SETAFFINITY |
167 | if (pthread_setaffinity_np(_pData->thread->native_handle(), sizeof(cpuset), &cpuset) != 0) |
168 | throw SystemException("Failed to set affinity" ); |
169 | #else |
170 | if (pthread_setaffinity_np(_pData->thread->native_handle(), &cpuset) != 0) |
171 | throw SystemException("Failed to set affinity" ); |
172 | #endif |
173 | #endif |
174 | #endif // defined unix & !defined mac os x |
175 | |
176 | #if POCO_OS == POCO_OS_MAC_OS_X |
177 | kern_return_t ret; |
178 | thread_affinity_policy policy; |
179 | policy.affinity_tag = cpu; |
180 | |
181 | ret = thread_policy_set(pthread_mach_thread_np(_pData->thread->native_handle()), |
182 | THREAD_AFFINITY_POLICY, |
183 | (thread_policy_t)&policy, |
184 | THREAD_AFFINITY_POLICY_COUNT); |
185 | if (ret != KERN_SUCCESS) |
186 | { |
187 | throw SystemException("Failed to set affinity" ); |
188 | } |
189 | #endif |
190 | yieldImpl(); |
191 | _pData->cpu = cpu; |
192 | } |
193 | |
194 | |
195 | int ThreadImpl::getAffinityImpl() const |
196 | { |
197 | int cpuSet = -1; |
198 | #if defined (POCO_OS_FAMILY_UNIX) && POCO_OS != POCO_OS_MAC_OS_X && POCO_OS != POCO_OS_FREE_BSD |
199 | #ifdef HAVE_PTHREAD_SETAFFINITY_NP |
200 | cpu_set_t cpuset; |
201 | CPU_ZERO(&cpuset); |
202 | #ifdef HAVE_THREE_PARAM_SCHED_SETAFFINITY |
203 | if (pthread_getaffinity_np(_pData->thread->native_handle(), sizeof(cpuset), &cpuset) != 0) |
204 | throw SystemException("Failed to get affinity" , errno); |
205 | #else |
206 | if (pthread_getaffinity_np(_pData->thread->native_handle(), &cpuset) != 0) |
207 | throw SystemException("Failed to get affinity" , errno); |
208 | #endif |
209 | int cpuCount = Environment::processorCount(); |
210 | for (int i = 0; i < cpuCount; i++) |
211 | { |
212 | if (CPU_ISSET(i, &cpuset)) |
213 | { |
214 | cpuSet = i; |
215 | break; |
216 | } |
217 | } |
218 | #endif |
219 | #endif // defined unix & !defined mac os x |
220 | |
221 | #if POCO_OS == POCO_OS_MAC_OS_X |
222 | kern_return_t ret; |
223 | thread_affinity_policy policy; |
224 | mach_msg_type_number_t count = THREAD_AFFINITY_POLICY_COUNT; |
225 | boolean_t get_default = false; |
226 | ret = thread_policy_get(pthread_mach_thread_np(_pData->thread->native_handle()), |
227 | THREAD_AFFINITY_POLICY, |
228 | (thread_policy_t)&policy, |
229 | &count, |
230 | &get_default); |
231 | if (ret != KERN_SUCCESS) |
232 | { |
233 | throw SystemException("Failed to get affinity" , errno); |
234 | } |
235 | cpuSet = policy.affinity_tag; |
236 | int cpuCount = Environment::processorCount(); |
237 | if (cpuSet >= cpuCount) |
238 | cpuSet = -1; |
239 | |
240 | #endif |
241 | return cpuSet; |
242 | } |
243 | |
244 | |
245 | } // namespace Poco |
246 | |