• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/resource.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 
17 #include <memory>
18 
19 #include "base/debug/activity_tracker.h"
20 #include "base/lazy_instance.h"
21 #include "base/logging.h"
22 #include "base/threading/platform_thread_internal_posix.h"
23 #include "base/threading/thread_id_name_manager.h"
24 #include "base/threading/thread_restrictions.h"
25 #include "build/build_config.h"
26 
27 #if defined(OS_LINUX)
28 #include <sys/syscall.h>
29 #endif
30 
31 namespace base {
32 
33 void InitThreading();
34 void TerminateOnThread();
35 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes);
36 
37 namespace {
38 
39 struct ThreadParams {
ThreadParamsbase::__anon73da1b830111::ThreadParams40   ThreadParams()
41       : delegate(NULL), joinable(false), priority(ThreadPriority::NORMAL) {}
42 
43   PlatformThread::Delegate* delegate;
44   bool joinable;
45   ThreadPriority priority;
46 };
47 
ThreadFunc(void * params)48 void* ThreadFunc(void* params) {
49   PlatformThread::Delegate* delegate = nullptr;
50 
51   {
52     std::unique_ptr<ThreadParams> thread_params(
53         static_cast<ThreadParams*>(params));
54 
55     delegate = thread_params->delegate;
56     if (!thread_params->joinable)
57       base::ThreadRestrictions::SetSingletonAllowed(false);
58 
59 #if !defined(OS_NACL)
60     // Threads on linux/android may inherit their priority from the thread
61     // where they were created. This explicitly sets the priority of all new
62     // threads.
63     PlatformThread::SetCurrentThreadPriority(thread_params->priority);
64 #endif
65   }
66 
67   ThreadIdNameManager::GetInstance()->RegisterThread(
68       PlatformThread::CurrentHandle().platform_handle(),
69       PlatformThread::CurrentId());
70 
71   delegate->ThreadMain();
72 
73   ThreadIdNameManager::GetInstance()->RemoveName(
74       PlatformThread::CurrentHandle().platform_handle(),
75       PlatformThread::CurrentId());
76 
77   base::TerminateOnThread();
78   return NULL;
79 }
80 
CreateThread(size_t stack_size,bool joinable,PlatformThread::Delegate * delegate,PlatformThreadHandle * thread_handle,ThreadPriority priority)81 bool CreateThread(size_t stack_size,
82                   bool joinable,
83                   PlatformThread::Delegate* delegate,
84                   PlatformThreadHandle* thread_handle,
85                   ThreadPriority priority) {
86   DCHECK(thread_handle);
87   base::InitThreading();
88 
89   pthread_attr_t attributes;
90   pthread_attr_init(&attributes);
91 
92   // Pthreads are joinable by default, so only specify the detached
93   // attribute if the thread should be non-joinable.
94   if (!joinable)
95     pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
96 
97   // Get a better default if available.
98   if (stack_size == 0)
99     stack_size = base::GetDefaultThreadStackSize(attributes);
100 
101   if (stack_size > 0)
102     pthread_attr_setstacksize(&attributes, stack_size);
103 
104   std::unique_ptr<ThreadParams> params(new ThreadParams);
105   params->delegate = delegate;
106   params->joinable = joinable;
107   params->priority = priority;
108 
109   pthread_t handle;
110   int err = pthread_create(&handle, &attributes, ThreadFunc, params.get());
111   bool success = !err;
112   if (success) {
113     // ThreadParams should be deleted on the created thread after used.
114     ignore_result(params.release());
115   } else {
116     // Value of |handle| is undefined if pthread_create fails.
117     handle = 0;
118     errno = err;
119     PLOG(ERROR) << "pthread_create";
120   }
121   *thread_handle = PlatformThreadHandle(handle);
122 
123   pthread_attr_destroy(&attributes);
124 
125   return success;
126 }
127 
128 }  // namespace
129 
130 // static
CurrentId()131 PlatformThreadId PlatformThread::CurrentId() {
132   // Pthreads doesn't have the concept of a thread ID, so we have to reach down
133   // into the kernel.
134 #if defined(OS_MACOSX)
135   return pthread_mach_thread_np(pthread_self());
136 #elif defined(OS_LINUX)
137   return syscall(__NR_gettid);
138 #elif defined(OS_ANDROID)
139   return gettid();
140 #elif defined(OS_SOLARIS) || defined(OS_QNX)
141   return pthread_self();
142 #elif defined(OS_NACL) && defined(__GLIBC__)
143   return pthread_self();
144 #elif defined(OS_NACL) && !defined(__GLIBC__)
145   // Pointers are 32-bits in NaCl.
146   return reinterpret_cast<int32_t>(pthread_self());
147 #elif defined(OS_POSIX)
148   return reinterpret_cast<int64_t>(pthread_self());
149 #endif
150 }
151 
152 // static
CurrentRef()153 PlatformThreadRef PlatformThread::CurrentRef() {
154   return PlatformThreadRef(pthread_self());
155 }
156 
157 // static
CurrentHandle()158 PlatformThreadHandle PlatformThread::CurrentHandle() {
159   return PlatformThreadHandle(pthread_self());
160 }
161 
162 // static
YieldCurrentThread()163 void PlatformThread::YieldCurrentThread() {
164   sched_yield();
165 }
166 
167 // static
Sleep(TimeDelta duration)168 void PlatformThread::Sleep(TimeDelta duration) {
169   struct timespec sleep_time, remaining;
170 
171   // Break the duration into seconds and nanoseconds.
172   // NOTE: TimeDelta's microseconds are int64s while timespec's
173   // nanoseconds are longs, so this unpacking must prevent overflow.
174   sleep_time.tv_sec = duration.InSeconds();
175   duration -= TimeDelta::FromSeconds(sleep_time.tv_sec);
176   sleep_time.tv_nsec = duration.InMicroseconds() * 1000;  // nanoseconds
177 
178   while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
179     sleep_time = remaining;
180 }
181 
182 // static
GetName()183 const char* PlatformThread::GetName() {
184   return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
185 }
186 
187 // static
CreateWithPriority(size_t stack_size,Delegate * delegate,PlatformThreadHandle * thread_handle,ThreadPriority priority)188 bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
189                                         PlatformThreadHandle* thread_handle,
190                                         ThreadPriority priority) {
191   return CreateThread(stack_size, true /* joinable thread */, delegate,
192                       thread_handle, priority);
193 }
194 
195 // static
CreateNonJoinable(size_t stack_size,Delegate * delegate)196 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
197   return CreateNonJoinableWithPriority(stack_size, delegate,
198                                        ThreadPriority::NORMAL);
199 }
200 
201 // static
CreateNonJoinableWithPriority(size_t stack_size,Delegate * delegate,ThreadPriority priority)202 bool PlatformThread::CreateNonJoinableWithPriority(size_t stack_size,
203                                                    Delegate* delegate,
204                                                    ThreadPriority priority) {
205   PlatformThreadHandle unused;
206 
207   bool result = CreateThread(stack_size, false /* non-joinable thread */,
208                              delegate, &unused, priority);
209   return result;
210 }
211 
212 // static
Join(PlatformThreadHandle thread_handle)213 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
214   // Record the event that this thread is blocking upon (for hang diagnosis).
215   base::debug::ScopedThreadJoinActivity thread_activity(&thread_handle);
216 
217   // Joining another thread may block the current thread for a long time, since
218   // the thread referred to by |thread_handle| may still be running long-lived /
219   // blocking tasks.
220   base::ThreadRestrictions::AssertIOAllowed();
221   CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), NULL));
222 }
223 
224 // static
Detach(PlatformThreadHandle thread_handle)225 void PlatformThread::Detach(PlatformThreadHandle thread_handle) {
226   CHECK_EQ(0, pthread_detach(thread_handle.platform_handle()));
227 }
228 
229 // Mac has its own Set/GetCurrentThreadPriority() implementations.
230 #if !defined(OS_MACOSX)
231 
232 // static
CanIncreaseCurrentThreadPriority()233 bool PlatformThread::CanIncreaseCurrentThreadPriority() {
234 #if defined(OS_NACL)
235   return false;
236 #else
237   // Only root can raise thread priority on POSIX environment. On Linux, users
238   // who have CAP_SYS_NICE permission also can raise the thread priority, but
239   // libcap.so would be needed to check the capability.
240   return geteuid() == 0;
241 #endif  // defined(OS_NACL)
242 }
243 
244 // static
SetCurrentThreadPriority(ThreadPriority priority)245 void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
246 #if defined(OS_NACL)
247   NOTIMPLEMENTED();
248 #else
249   if (internal::SetCurrentThreadPriorityForPlatform(priority))
250     return;
251 
252   // setpriority(2) should change the whole thread group's (i.e. process)
253   // priority. However, as stated in the bugs section of
254   // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current
255   // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
256   // attribute". Also, 0 is prefered to the current thread id since it is
257   // equivalent but makes sandboxing easier (https://crbug.com/399473).
258   const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
259   if (setpriority(PRIO_PROCESS, 0, nice_setting)) {
260     DVPLOG(1) << "Failed to set nice value of thread ("
261               << PlatformThread::CurrentId() << ") to " << nice_setting;
262   }
263 #endif  // defined(OS_NACL)
264 }
265 
266 // static
GetCurrentThreadPriority()267 ThreadPriority PlatformThread::GetCurrentThreadPriority() {
268 #if defined(OS_NACL)
269   NOTIMPLEMENTED();
270   return ThreadPriority::NORMAL;
271 #else
272   // Mirrors SetCurrentThreadPriority()'s implementation.
273   ThreadPriority platform_specific_priority;
274   if (internal::GetCurrentThreadPriorityForPlatform(
275           &platform_specific_priority)) {
276     return platform_specific_priority;
277   }
278 
279   // Need to clear errno before calling getpriority():
280   // http://man7.org/linux/man-pages/man2/getpriority.2.html
281   errno = 0;
282   int nice_value = getpriority(PRIO_PROCESS, 0);
283   if (errno != 0) {
284     DVPLOG(1) << "Failed to get nice value of thread ("
285               << PlatformThread::CurrentId() << ")";
286     return ThreadPriority::NORMAL;
287   }
288 
289   return internal::NiceValueToThreadPriority(nice_value);
290 #endif  // !defined(OS_NACL)
291 }
292 
293 #endif  // !defined(OS_MACOSX)
294 
295 }  // namespace base
296