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
40namespace Poco {
41
42
43int 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
67int 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
89void 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
106void 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
124int 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
136int 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
148void ThreadImpl::setStackSizeImpl(int size)
149{
150 _pData->stackSize = size;
151 // not supported
152}
153
154
155void 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
191int 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
240long 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