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