1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/threading/platform_thread.h"
6 
7 #include <errno.h>
8 #include <pthread.h>
9 #include <sched.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <sys/time.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 
16 #include <memory>
17 
18 #include "base/debug/activity_tracker.h"
19 #include "base/lazy_instance.h"
20 #include "base/logging.h"
21 #include "base/no_destructor.h"
22 #include "base/threading/platform_thread_internal_posix.h"
23 #include "base/threading/scoped_blocking_call.h"
24 #include "base/threading/thread_id_name_manager.h"
25 #include "build/build_config.h"
26 
27 #if !defined(OS_MACOSX) && !defined(OS_FUCHSIA) && !defined(OS_NACL)
28 #include "base/posix/can_lower_nice_to.h"
29 #endif
30 
31 #if defined(OS_LINUX)
32 #include <sys/syscall.h>
33 #endif
34 
35 #if defined(OS_FUCHSIA)
36 #include <zircon/process.h>
37 #else
38 #include <sys/resource.h>
39 #endif
40 
41 namespace base {
42 
43 void InitThreading();
44 void TerminateOnThread();
45 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes);
46 
47 namespace {
48 
49 struct ThreadParams {
ThreadParamsbase::__anond33134d10111::ThreadParams50   ThreadParams()
51       : delegate(nullptr), joinable(false), priority(ThreadPriority::NORMAL) {}
52 
53   PlatformThread::Delegate* delegate;
54   bool joinable;
55   ThreadPriority priority;
56 };
57 
ThreadFunc(void * params)58 void* ThreadFunc(void* params) {
59   PlatformThread::Delegate* delegate = nullptr;
60 
61   {
62     std::unique_ptr<ThreadParams> thread_params(
63         static_cast<ThreadParams*>(params));
64 
65     delegate = thread_params->delegate;
66     if (!thread_params->joinable)
67       base::ThreadRestrictions::SetSingletonAllowed(false);
68 
69 #if !defined(OS_NACL) && !defined(OS_BSD)
70     // Threads on linux/android may inherit their priority from the thread
71     // where they were created. This explicitly sets the priority of all new
72     // threads.
73     PlatformThread::SetCurrentThreadPriority(thread_params->priority);
74 #endif
75   }
76 
77   ThreadIdNameManager::GetInstance()->RegisterThread(
78       PlatformThread::CurrentHandle().platform_handle(),
79       PlatformThread::CurrentId());
80 
81   delegate->ThreadMain();
82 
83   ThreadIdNameManager::GetInstance()->RemoveName(
84       PlatformThread::CurrentHandle().platform_handle(),
85       PlatformThread::CurrentId());
86 
87   base::TerminateOnThread();
88   return nullptr;
89 }
90 
CreateThread(size_t stack_size,bool joinable,PlatformThread::Delegate * delegate,PlatformThreadHandle * thread_handle,ThreadPriority priority)91 bool CreateThread(size_t stack_size,
92                   bool joinable,
93                   PlatformThread::Delegate* delegate,
94                   PlatformThreadHandle* thread_handle,
95                   ThreadPriority priority) {
96   DCHECK(thread_handle);
97   base::InitThreading();
98 
99   pthread_attr_t attributes;
100   pthread_attr_init(&attributes);
101 
102   // Pthreads are joinable by default, so only specify the detached
103   // attribute if the thread should be non-joinable.
104   if (!joinable)
105     pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
106 
107   // Get a better default if available.
108   if (stack_size == 0)
109     stack_size = base::GetDefaultThreadStackSize(attributes);
110 
111   if (stack_size > 0)
112     pthread_attr_setstacksize(&attributes, stack_size);
113 
114   std::unique_ptr<ThreadParams> params(new ThreadParams);
115   params->delegate = delegate;
116   params->joinable = joinable;
117   params->priority = priority;
118 
119   pthread_t handle;
120   int err = pthread_create(&handle, &attributes, ThreadFunc, params.get());
121   bool success = !err;
122   if (success) {
123     // ThreadParams should be deleted on the created thread after used.
124     ignore_result(params.release());
125   } else {
126     // Value of |handle| is undefined if pthread_create fails.
127     handle = 0;
128     errno = err;
129     PLOG(ERROR) << "pthread_create";
130   }
131   *thread_handle = PlatformThreadHandle(handle);
132 
133   pthread_attr_destroy(&attributes);
134 
135   return success;
136 }
137 
138 #if defined(OS_LINUX)
139 
140 // Store the thread ids in local storage since calling the SWI can
141 // expensive and PlatformThread::CurrentId is used liberally. Clear
142 // the stored value after a fork() because forking changes the thread
143 // id. Forking without going through fork() (e.g. clone()) is not
144 // supported, but there is no known usage. Using thread_local is
145 // fine here (despite being banned) since it is going to be allowed
146 // but is blocked on a clang bug for Mac (https://crbug.com/829078)
147 // and we can't use ThreadLocalStorage because of re-entrancy due to
148 // CHECK/DCHECKs.
149 thread_local pid_t g_thread_id = -1;
150 
151 class InitAtFork {
152  public:
InitAtFork()153   InitAtFork() { pthread_atfork(nullptr, nullptr, internal::ClearTidCache); }
154 };
155 
156 #endif  // defined(OS_LINUX)
157 
158 }  // namespace
159 
160 #if defined(OS_LINUX)
161 
162 namespace internal {
163 
ClearTidCache()164 void ClearTidCache() {
165   g_thread_id = -1;
166 }
167 
168 }  // namespace internal
169 
170 #endif  // defined(OS_LINUX)
171 
172 // static
CurrentId()173 PlatformThreadId PlatformThread::CurrentId() {
174   // Pthreads doesn't have the concept of a thread ID, so we have to reach down
175   // into the kernel.
176 #if defined(OS_MACOSX)
177   return pthread_mach_thread_np(pthread_self());
178 #elif defined(OS_LINUX)
179   static NoDestructor<InitAtFork> init_at_fork;
180   if (g_thread_id == -1) {
181     g_thread_id = syscall(__NR_gettid);
182   } else {
183     DCHECK_EQ(g_thread_id, syscall(__NR_gettid))
184         << "Thread id stored in TLS is different from thread id returned by "
185            "the system. It is likely that the process was forked without going "
186            "through fork().";
187   }
188   return g_thread_id;
189 #elif defined(OS_ANDROID)
190   return gettid();
191 #elif defined(OS_FUCHSIA)
192   return zx_thread_self();
193 #elif defined(OS_SOLARIS) || defined(OS_QNX)
194   return pthread_self();
195 #elif defined(OS_NACL) && defined(__GLIBC__)
196   return pthread_self();
197 #elif defined(OS_NACL) && !defined(__GLIBC__)
198   // Pointers are 32-bits in NaCl.
199   return reinterpret_cast<int32_t>(pthread_self());
200 #elif defined(OS_POSIX) && defined(OS_AIX)
201   return pthread_self();
202 #elif defined(OS_POSIX) && !defined(OS_AIX)
203   return reinterpret_cast<int64_t>(pthread_self());
204 #endif
205 }
206 
207 // static
CurrentRef()208 PlatformThreadRef PlatformThread::CurrentRef() {
209   return PlatformThreadRef(pthread_self());
210 }
211 
212 // static
CurrentHandle()213 PlatformThreadHandle PlatformThread::CurrentHandle() {
214   return PlatformThreadHandle(pthread_self());
215 }
216 
217 // static
YieldCurrentThread()218 void PlatformThread::YieldCurrentThread() {
219   sched_yield();
220 }
221 
222 // static
Sleep(TimeDelta duration)223 void PlatformThread::Sleep(TimeDelta duration) {
224   struct timespec sleep_time, remaining;
225 
226   // Break the duration into seconds and nanoseconds.
227   // NOTE: TimeDelta's microseconds are int64s while timespec's
228   // nanoseconds are longs, so this unpacking must prevent overflow.
229   sleep_time.tv_sec = duration.InSeconds();
230   duration -= TimeDelta::FromSeconds(sleep_time.tv_sec);
231   sleep_time.tv_nsec = duration.InMicroseconds() * 1000;  // nanoseconds
232 
233   while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
234     sleep_time = remaining;
235 }
236 
237 // static
GetName()238 const char* PlatformThread::GetName() {
239   return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
240 }
241 
242 // static
CreateWithPriority(size_t stack_size,Delegate * delegate,PlatformThreadHandle * thread_handle,ThreadPriority priority)243 bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
244                                         PlatformThreadHandle* thread_handle,
245                                         ThreadPriority priority) {
246   return CreateThread(stack_size, true /* joinable thread */, delegate,
247                       thread_handle, priority);
248 }
249 
250 // static
CreateNonJoinable(size_t stack_size,Delegate * delegate)251 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
252   return CreateNonJoinableWithPriority(stack_size, delegate,
253                                        ThreadPriority::NORMAL);
254 }
255 
256 // static
CreateNonJoinableWithPriority(size_t stack_size,Delegate * delegate,ThreadPriority priority)257 bool PlatformThread::CreateNonJoinableWithPriority(size_t stack_size,
258                                                    Delegate* delegate,
259                                                    ThreadPriority priority) {
260   PlatformThreadHandle unused;
261 
262   bool result = CreateThread(stack_size, false /* non-joinable thread */,
263                              delegate, &unused, priority);
264   return result;
265 }
266 
267 // static
Join(PlatformThreadHandle thread_handle)268 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
269   // Record the event that this thread is blocking upon (for hang diagnosis).
270   base::debug::ScopedThreadJoinActivity thread_activity(&thread_handle);
271 
272   // Joining another thread may block the current thread for a long time, since
273   // the thread referred to by |thread_handle| may still be running long-lived /
274   // blocking tasks.
275   base::internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
276       FROM_HERE, base::BlockingType::MAY_BLOCK);
277   CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), nullptr));
278 }
279 
280 // static
Detach(PlatformThreadHandle thread_handle)281 void PlatformThread::Detach(PlatformThreadHandle thread_handle) {
282   CHECK_EQ(0, pthread_detach(thread_handle.platform_handle()));
283 }
284 
285 // Mac and Fuchsia have their own Set/GetCurrentThreadPriority()
286 // implementations.
287 #if !defined(OS_MACOSX) && !defined(OS_FUCHSIA)
288 
289 // static
CanIncreaseThreadPriority(ThreadPriority priority)290 bool PlatformThread::CanIncreaseThreadPriority(ThreadPriority priority) {
291 #if defined(OS_NACL)
292   return false;
293 #else
294   auto platform_specific_ability =
295       internal::CanIncreaseCurrentThreadPriorityForPlatform(priority);
296   if (platform_specific_ability)
297     return platform_specific_ability.value();
298 
299   return internal::CanLowerNiceTo(
300       internal::ThreadPriorityToNiceValue(priority));
301 #endif  // defined(OS_NACL)
302 }
303 
304 // static
SetCurrentThreadPriorityImpl(ThreadPriority priority)305 void PlatformThread::SetCurrentThreadPriorityImpl(ThreadPriority priority) {
306 #if defined(OS_NACL)
307   NOTIMPLEMENTED();
308 #else
309   if (internal::SetCurrentThreadPriorityForPlatform(priority))
310     return;
311 
312   // setpriority(2) should change the whole thread group's (i.e. process)
313   // priority. However, as stated in the bugs section of
314   // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current
315   // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
316   // attribute". Also, 0 is prefered to the current thread id since it is
317   // equivalent but makes sandboxing easier (https://crbug.com/399473).
318   const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
319   if (setpriority(PRIO_PROCESS, 0, nice_setting)) {
320     DVPLOG(1) << "Failed to set nice value of thread ("
321               << PlatformThread::CurrentId() << ") to " << nice_setting;
322   }
323 #endif  // defined(OS_NACL)
324 }
325 
326 // static
GetCurrentThreadPriority()327 ThreadPriority PlatformThread::GetCurrentThreadPriority() {
328 #if defined(OS_NACL)
329   NOTIMPLEMENTED();
330   return ThreadPriority::NORMAL;
331 #else
332   // Mirrors SetCurrentThreadPriority()'s implementation.
333   auto platform_specific_priority =
334       internal::GetCurrentThreadPriorityForPlatform();
335   if (platform_specific_priority)
336     return platform_specific_priority.value();
337 
338   // Need to clear errno before calling getpriority():
339   // http://man7.org/linux/man-pages/man2/getpriority.2.html
340   errno = 0;
341   int nice_value = getpriority(PRIO_PROCESS, 0);
342   if (errno != 0) {
343     DVPLOG(1) << "Failed to get nice value of thread ("
344               << PlatformThread::CurrentId() << ")";
345     return ThreadPriority::NORMAL;
346   }
347 
348   return internal::NiceValueToThreadPriority(nice_value);
349 #endif  // !defined(OS_NACL)
350 }
351 
352 #endif  // !defined(OS_MACOSX) && !defined(OS_FUCHSIA)
353 
354 // static
GetDefaultThreadStackSize()355 size_t PlatformThread::GetDefaultThreadStackSize() {
356   pthread_attr_t attributes;
357   pthread_attr_init(&attributes);
358   return base::GetDefaultThreadStackSize(attributes);
359 }
360 
361 }  // namespace base
362