platform_thread_posix.cc (14126B)
1 // Copyright 2012 The Chromium Authors 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/notreached.h" 6 #include "base/threading/platform_thread.h" 7 8 #include <errno.h> 9 #include <pthread.h> 10 #include <sched.h> 11 #include <stddef.h> 12 #include <stdint.h> 13 #include <sys/time.h> 14 #include <sys/types.h> 15 #include <unistd.h> 16 17 #include <memory> 18 #include <tuple> 19 20 #include "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_buildflags.h" 21 #include "base/compiler_specific.h" 22 #include "base/lazy_instance.h" 23 #include "base/logging.h" 24 #include "base/memory/raw_ptr.h" 25 #include "base/threading/platform_thread_internal_posix.h" 26 #include "base/threading/scoped_blocking_call.h" 27 #include "base/threading/thread_id_name_manager.h" 28 #include "base/threading/thread_restrictions.h" 29 #include "build/build_config.h" 30 31 #if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA) && !BUILDFLAG(IS_NACL) 32 #include "base/posix/can_lower_nice_to.h" 33 #endif 34 35 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 36 #include <sys/syscall.h> 37 #include <atomic> 38 #endif 39 40 #if BUILDFLAG(IS_FUCHSIA) 41 #include <zircon/process.h> 42 #else 43 #include <sys/resource.h> 44 #endif 45 46 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN) 47 #include "base/allocator/partition_allocator/src/partition_alloc/starscan/pcscan.h" 48 #include "base/allocator/partition_allocator/src/partition_alloc/starscan/stack/stack.h" 49 #endif 50 51 namespace base { 52 53 void InitThreading(); 54 void TerminateOnThread(); 55 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes); 56 57 namespace { 58 59 #if !defined(MOZ_SANDBOX) 60 struct ThreadParams { 61 ThreadParams() = default; 62 63 raw_ptr<PlatformThread::Delegate> delegate = nullptr; 64 bool joinable = false; 65 ThreadType thread_type = ThreadType::kDefault; 66 MessagePumpType message_pump_type = MessagePumpType::DEFAULT; 67 }; 68 69 void* ThreadFunc(void* params) { 70 PlatformThread::Delegate* delegate = nullptr; 71 72 { 73 std::unique_ptr<ThreadParams> thread_params( 74 static_cast<ThreadParams*>(params)); 75 76 delegate = thread_params->delegate; 77 if (!thread_params->joinable) 78 base::DisallowSingleton(); 79 80 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN) 81 partition_alloc::internal::PCScan::NotifyThreadCreated( 82 partition_alloc::internal::GetStackPointer()); 83 #endif 84 85 #if !BUILDFLAG(IS_NACL) 86 #if BUILDFLAG(IS_APPLE) 87 PlatformThread::SetCurrentThreadRealtimePeriodValue( 88 delegate->GetRealtimePeriod()); 89 #endif 90 91 // Threads on linux/android may inherit their priority from the thread 92 // where they were created. This explicitly sets the priority of all new 93 // threads. 94 PlatformThread::SetCurrentThreadType(thread_params->thread_type); 95 #endif // !BUILDFLAG(IS_NACL) 96 } 97 98 ThreadIdNameManager::GetInstance()->RegisterThread( 99 PlatformThread::CurrentHandle().platform_handle(), 100 PlatformThread::CurrentId()); 101 102 delegate->ThreadMain(); 103 104 ThreadIdNameManager::GetInstance()->RemoveName( 105 PlatformThread::CurrentHandle().platform_handle(), 106 PlatformThread::CurrentId()); 107 108 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN) 109 partition_alloc::internal::PCScan::NotifyThreadDestroyed(); 110 #endif 111 112 base::TerminateOnThread(); 113 return nullptr; 114 } 115 116 bool CreateThread(size_t stack_size, 117 bool joinable, 118 PlatformThread::Delegate* delegate, 119 PlatformThreadHandle* thread_handle, 120 ThreadType thread_type, 121 MessagePumpType message_pump_type) { 122 DCHECK(thread_handle); 123 base::InitThreading(); 124 125 pthread_attr_t attributes; 126 pthread_attr_init(&attributes); 127 128 // Pthreads are joinable by default, so only specify the detached 129 // attribute if the thread should be non-joinable. 130 if (!joinable) 131 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); 132 133 // Get a better default if available. 134 if (stack_size == 0) 135 stack_size = base::GetDefaultThreadStackSize(attributes); 136 137 if (stack_size > 0) 138 pthread_attr_setstacksize(&attributes, stack_size); 139 140 std::unique_ptr<ThreadParams> params(new ThreadParams); 141 params->delegate = delegate; 142 params->joinable = joinable; 143 params->thread_type = thread_type; 144 params->message_pump_type = message_pump_type; 145 146 pthread_t handle; 147 int err = pthread_create(&handle, &attributes, ThreadFunc, params.get()); 148 bool success = !err; 149 if (success) { 150 // ThreadParams should be deleted on the created thread after used. 151 std::ignore = params.release(); 152 } else { 153 // Value of |handle| is undefined if pthread_create fails. 154 handle = 0; 155 errno = err; 156 PLOG(ERROR) << "pthread_create"; 157 } 158 *thread_handle = PlatformThreadHandle(handle); 159 160 pthread_attr_destroy(&attributes); 161 162 return success; 163 } 164 #endif 165 166 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 167 168 // Store the thread ids in local storage since calling the SWI can be 169 // expensive and PlatformThread::CurrentId is used liberally. 170 thread_local pid_t g_thread_id = -1; 171 172 // A boolean value that indicates that the value stored in |g_thread_id| on the 173 // main thread is invalid, because it hasn't been updated since the process 174 // forked. 175 // 176 // This used to work by setting |g_thread_id| to -1 in a pthread_atfork handler. 177 // However, when a multithreaded process forks, it is only allowed to call 178 // async-signal-safe functions until it calls an exec() syscall. However, 179 // accessing TLS may allocate (see crbug.com/1275748), which is not 180 // async-signal-safe and therefore causes deadlocks, corruption, and crashes. 181 // 182 // It's Atomic to placate TSAN. 183 std::atomic<bool> g_main_thread_tid_cache_valid = false; 184 185 // Tracks whether the current thread is the main thread, and therefore whether 186 // |g_main_thread_tid_cache_valid| is relevant for the current thread. This is 187 // also updated by PlatformThread::CurrentId(). 188 thread_local bool g_is_main_thread = true; 189 190 class InitAtFork { 191 public: 192 InitAtFork() { 193 pthread_atfork(nullptr, nullptr, internal::InvalidateTidCache); 194 } 195 }; 196 197 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 198 199 } // namespace 200 201 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 202 203 namespace internal { 204 205 void InvalidateTidCache() { 206 g_main_thread_tid_cache_valid.store(false, std::memory_order_relaxed); 207 } 208 209 } // namespace internal 210 211 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 212 213 // static 214 PlatformThreadId PlatformThreadBase::CurrentId() { 215 // Pthreads doesn't have the concept of a thread ID, so we have to reach down 216 // into the kernel. 217 #if BUILDFLAG(IS_APPLE) 218 return pthread_mach_thread_np(pthread_self()); 219 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 220 // Workaround false-positive MSAN use-of-uninitialized-value on 221 // thread_local storage for loaded libraries: 222 // https://github.com/google/sanitizers/issues/1265 223 MSAN_UNPOISON(&g_thread_id, sizeof(pid_t)); 224 MSAN_UNPOISON(&g_is_main_thread, sizeof(bool)); 225 static InitAtFork init_at_fork; 226 if (g_thread_id == -1 || 227 (g_is_main_thread && 228 !g_main_thread_tid_cache_valid.load(std::memory_order_relaxed))) { 229 // Update the cached tid. 230 g_thread_id = static_cast<pid_t>(syscall(__NR_gettid)); 231 // If this is the main thread, we can mark the tid_cache as valid. 232 // Otherwise, stop the current thread from always entering this slow path. 233 if (g_thread_id == getpid()) { 234 g_main_thread_tid_cache_valid.store(true, std::memory_order_relaxed); 235 } else { 236 g_is_main_thread = false; 237 } 238 } else { 239 #if DCHECK_IS_ON() 240 if (g_thread_id != syscall(__NR_gettid)) { 241 RAW_LOG( 242 FATAL, 243 "Thread id stored in TLS is different from thread id returned by " 244 "the system. It is likely that the process was forked without going " 245 "through fork()."); 246 } 247 #endif 248 } 249 return g_thread_id; 250 #elif BUILDFLAG(IS_ANDROID) 251 // Note: do not cache the return value inside a thread_local variable on 252 // Android (as above). The reasons are: 253 // - thread_local is slow on Android (goes through emutls) 254 // - gettid() is fast, since its return value is cached in pthread (in the 255 // thread control block of pthread). See gettid.c in bionic. 256 return gettid(); 257 #elif BUILDFLAG(IS_FUCHSIA) 258 return zx_thread_self(); 259 #elif BUILDFLAG(IS_SOLARIS) || BUILDFLAG(IS_QNX) 260 return pthread_self(); 261 #elif BUILDFLAG(IS_NACL) && defined(__GLIBC__) 262 return pthread_self(); 263 #elif BUILDFLAG(IS_NACL) && !defined(__GLIBC__) 264 // Pointers are 32-bits in NaCl. 265 return reinterpret_cast<int32_t>(pthread_self()); 266 #elif BUILDFLAG(IS_POSIX) && BUILDFLAG(IS_AIX) 267 return pthread_self(); 268 #elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_AIX) 269 return reinterpret_cast<int64_t>(pthread_self()); 270 #endif 271 } 272 273 // static 274 PlatformThreadRef PlatformThreadBase::CurrentRef() { 275 return PlatformThreadRef(pthread_self()); 276 } 277 278 // static 279 PlatformThreadHandle PlatformThreadBase::CurrentHandle() { 280 return PlatformThreadHandle(pthread_self()); 281 } 282 283 #if !BUILDFLAG(IS_APPLE) 284 // static 285 void PlatformThreadBase::YieldCurrentThread() { 286 sched_yield(); 287 } 288 #endif // !BUILDFLAG(IS_APPLE) 289 290 // static 291 void PlatformThreadBase::Sleep(TimeDelta duration) { 292 struct timespec sleep_time, remaining; 293 294 // Break the duration into seconds and nanoseconds. 295 // NOTE: TimeDelta's microseconds are int64s while timespec's 296 // nanoseconds are longs, so this unpacking must prevent overflow. 297 sleep_time.tv_sec = static_cast<time_t>(duration.InSeconds()); 298 duration -= Seconds(sleep_time.tv_sec); 299 sleep_time.tv_nsec = static_cast<long>(duration.InMicroseconds() * 1000); 300 301 while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) 302 sleep_time = remaining; 303 } 304 305 // static 306 const char* PlatformThreadBase::GetName() { 307 return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); 308 } 309 310 #if !defined(MOZ_SANDBOX) 311 // static 312 bool PlatformThreadBase::CreateWithType(size_t stack_size, 313 Delegate* delegate, 314 PlatformThreadHandle* thread_handle, 315 ThreadType thread_type, 316 MessagePumpType pump_type_hint) { 317 return CreateThread(stack_size, true /* joinable thread */, delegate, 318 thread_handle, thread_type, pump_type_hint); 319 } 320 321 // static 322 bool PlatformThreadBase::CreateNonJoinable(size_t stack_size, Delegate* delegate) { 323 return CreateNonJoinableWithType(stack_size, delegate, ThreadType::kDefault); 324 } 325 326 // static 327 bool PlatformThreadBase::CreateNonJoinableWithType(size_t stack_size, 328 Delegate* delegate, 329 ThreadType thread_type, 330 MessagePumpType pump_type_hint) { 331 PlatformThreadHandle unused; 332 333 bool result = CreateThread(stack_size, false /* non-joinable thread */, 334 delegate, &unused, thread_type, pump_type_hint); 335 return result; 336 } 337 #endif 338 339 // static 340 void PlatformThreadBase::Join(PlatformThreadHandle thread_handle) { 341 // Joining another thread may block the current thread for a long time, since 342 // the thread referred to by |thread_handle| may still be running long-lived / 343 // blocking tasks. 344 base::internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call( 345 FROM_HERE, base::BlockingType::MAY_BLOCK); 346 CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), nullptr)); 347 } 348 349 // static 350 void PlatformThreadBase::Detach(PlatformThreadHandle thread_handle) { 351 CHECK_EQ(0, pthread_detach(thread_handle.platform_handle())); 352 } 353 354 // Mac and Fuchsia have their own SetCurrentThreadType() and 355 // GetCurrentThreadPriorityForTest() implementations. 356 #if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA) 357 358 #if !defined(MOZ_SANDBOX) 359 // static 360 bool PlatformThreadBase::CanChangeThreadType(ThreadType from, ThreadType to) { 361 #if BUILDFLAG(IS_NACL) 362 return false; 363 #else 364 if (from >= to) { 365 // Decreasing thread priority on POSIX is always allowed. 366 return true; 367 } 368 if (to == ThreadType::kRealtimeAudio) { 369 return internal::CanSetThreadTypeToRealtimeAudio(); 370 } 371 372 return internal::CanLowerNiceTo(internal::ThreadTypeToNiceValue(to)); 373 #endif // BUILDFLAG(IS_NACL) 374 } 375 #endif 376 377 namespace internal { 378 379 void SetCurrentThreadTypeImpl(ThreadType thread_type, 380 MessagePumpType pump_type_hint) { 381 #if BUILDFLAG(IS_NACL) 382 NOTIMPLEMENTED(); 383 #else 384 if (internal::SetCurrentThreadTypeForPlatform(thread_type, pump_type_hint)) 385 return; 386 387 // setpriority(2) should change the whole thread group's (i.e. process) 388 // priority. However, as stated in the bugs section of 389 // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current 390 // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread 391 // attribute". Also, 0 is prefered to the current thread id since it is 392 // equivalent but makes sandboxing easier (https://crbug.com/399473). 393 const int nice_setting = internal::ThreadTypeToNiceValue(thread_type); 394 if (setpriority(PRIO_PROCESS, 0, nice_setting)) { 395 DVPLOG(1) << "Failed to set nice value of thread (" 396 << PlatformThread::CurrentId() << ") to " << nice_setting; 397 } 398 #endif // BUILDFLAG(IS_NACL) 399 } 400 401 } // namespace internal 402 403 // static 404 ThreadPriorityForTest PlatformThreadBase::GetCurrentThreadPriorityForTest() { 405 #if BUILDFLAG(IS_NACL) 406 NOTIMPLEMENTED(); 407 return ThreadPriorityForTest::kNormal; 408 #else 409 // Mirrors SetCurrentThreadPriority()'s implementation. 410 auto platform_specific_priority = 411 internal::GetCurrentThreadPriorityForPlatformForTest(); // IN-TEST 412 if (platform_specific_priority) 413 return platform_specific_priority.value(); 414 415 int nice_value = internal::GetCurrentThreadNiceValue(); 416 417 return internal::NiceValueToThreadPriorityForTest(nice_value); // IN-TEST 418 #endif // !BUILDFLAG(IS_NACL) 419 } 420 421 #endif // !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA) 422 423 // static 424 size_t PlatformThreadBase::GetDefaultThreadStackSize() { 425 pthread_attr_t attributes; 426 pthread_attr_init(&attributes); 427 return base::GetDefaultThreadStackSize(attributes); 428 } 429 430 } // namespace base