diff options
21 files changed, 448 insertions, 202 deletions
diff --git a/base/base.gypi b/base/base.gypi index c802284..6492073 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -473,6 +473,8 @@ 'threading/non_thread_safe_impl.cc', 'threading/non_thread_safe_impl.h', 'threading/platform_thread.h', + 'threading/platform_thread_android.cc', + 'threading/platform_thread_linux.cc', 'threading/platform_thread_mac.mm', 'threading/platform_thread_posix.cc', 'threading/platform_thread_win.cc', @@ -655,8 +657,11 @@ 'threading/sequenced_worker_pool.cc', 'third_party/dynamic_annotations/dynamic_annotations.c', ], - # Metrics won't work in the NaCl sandbox. - 'sources/': [ ['exclude', '^metrics/'] ], + 'sources/': [ + # Metrics won't work in the NaCl sandbox. + ['exclude', '^metrics/'], + ['include', '^threading/platform_thread_linux\\.cc$'], + ], }], ['OS == "android" and >(nacl_untrusted_build)==0', { 'sources!': [ @@ -674,6 +679,12 @@ ['include', '^worker_pool_linux\\.cc$'], ], }], + ['OS == "android" and _toolset == "host" and host_os == "linux"', { + 'sources/': [ + # Pull in specific files for host builds. + ['include', '^threading/platform_thread_linux\\.cc$'], + ], + }], ['OS == "ios" and _toolset != "host"', { 'sources/': [ # Pull in specific Mac files for iOS (which have been filtered out diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc index 70d92ce..67254c1 100644 --- a/base/debug/trace_event_impl.cc +++ b/base/debug/trace_event_impl.cc @@ -977,7 +977,7 @@ void TraceLog::SetDisabled() { lock_.Release(); PlatformThread::Join(sampling_thread_handle_); lock_.Acquire(); - sampling_thread_handle_ = 0; + sampling_thread_handle_ = PlatformThreadHandle(); sampling_thread_.reset(); } diff --git a/base/synchronization/lock_unittest.cc b/base/synchronization/lock_unittest.cc index e87571d..16144755 100644 --- a/base/synchronization/lock_unittest.cc +++ b/base/synchronization/lock_unittest.cc @@ -51,7 +51,7 @@ class BasicLockTestThread : public PlatformThread::Delegate { TEST(LockTest, Basic) { Lock lock; BasicLockTestThread thread(&lock); - PlatformThreadHandle handle = kNullThreadHandle; + PlatformThreadHandle handle; ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); @@ -117,7 +117,7 @@ TEST(LockTest, TryLock) { // This thread will not be able to get the lock. { TryLockTestThread thread(&lock); - PlatformThreadHandle handle = kNullThreadHandle; + PlatformThreadHandle handle; ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); @@ -131,7 +131,7 @@ TEST(LockTest, TryLock) { // This thread will.... { TryLockTestThread thread(&lock); - PlatformThreadHandle handle = kNullThreadHandle; + PlatformThreadHandle handle; ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); @@ -178,7 +178,7 @@ TEST(LockTest, MutexTwoThreads) { int value = 0; MutexLockTestThread thread(&lock, &value); - PlatformThreadHandle handle = kNullThreadHandle; + PlatformThreadHandle handle; ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); @@ -196,9 +196,9 @@ TEST(LockTest, MutexFourThreads) { MutexLockTestThread thread1(&lock, &value); MutexLockTestThread thread2(&lock, &value); MutexLockTestThread thread3(&lock, &value); - PlatformThreadHandle handle1 = kNullThreadHandle; - PlatformThreadHandle handle2 = kNullThreadHandle; - PlatformThreadHandle handle3 = kNullThreadHandle; + PlatformThreadHandle handle1; + PlatformThreadHandle handle2; + PlatformThreadHandle handle3; ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1)); ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2)); diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h index 576695a..c597500 100644 --- a/base/threading/platform_thread.h +++ b/base/threading/platform_thread.h @@ -23,27 +23,66 @@ namespace base { -// PlatformThreadHandle should not be assumed to be a numeric type, since the -// standard intends to allow pthread_t to be a structure. This means you -// should not initialize it to a value, like 0. If it's a member variable, the -// constructor can safely "value initialize" using () in the initializer list. #if defined(OS_WIN) typedef DWORD PlatformThreadId; -typedef void* PlatformThreadHandle; // HANDLE -const PlatformThreadHandle kNullThreadHandle = NULL; #elif defined(OS_POSIX) -typedef pthread_t PlatformThreadHandle; -const PlatformThreadHandle kNullThreadHandle = 0; typedef pid_t PlatformThreadId; #endif -const PlatformThreadId kInvalidThreadId = 0; +class PlatformThreadHandle { + public: +#if defined(OS_WIN) + typedef void* Handle; +#elif defined(OS_POSIX) + typedef pthread_t Handle; +#endif + + PlatformThreadHandle() + : handle_(0), + id_(0) { + } + + explicit PlatformThreadHandle(Handle handle) + : handle_(handle), + id_(0) { + } + + PlatformThreadHandle(Handle handle, + PlatformThreadId id) + : handle_(handle), + id_(id) { + } + + bool is_equal(const PlatformThreadHandle& other) { + return handle_ == other.handle_; + } + + bool is_null() { + return !handle_; + } + + Handle platform_handle() { + return handle_; + } + + private: + friend class PlatformThread; + + Handle handle_; + PlatformThreadId id_; +}; + +const PlatformThreadId kInvalidThreadId(0); // Valid values for SetThreadPriority() enum ThreadPriority{ kThreadPriority_Normal, // Suitable for low-latency, glitch-resistant audio. - kThreadPriority_RealtimeAudio + kThreadPriority_RealtimeAudio, + // Suitable for threads which generate data for the display (at ~60Hz). + kThreadPriority_Display, + // Suitable for threads that shouldn't disrupt high priority work. + kThreadPriority_Background }; // A namespace for low-level thread functions. @@ -62,6 +101,9 @@ class BASE_EXPORT PlatformThread { // Gets the current thread id, which may be useful for logging purposes. static PlatformThreadId CurrentId(); + // Get the current handle. + static PlatformThreadHandle CurrentHandle(); + // Yield the current thread so another thread can be scheduled. static void YieldCurrentThread(); @@ -106,8 +148,6 @@ class BASE_EXPORT PlatformThread { // |thread_handle|. static void Join(PlatformThreadHandle thread_handle); - // Sets the priority of the thread specified in |handle| to |priority|. - // This does not work on Linux, use CreateWithPriority() instead. static void SetThreadPriority(PlatformThreadHandle handle, ThreadPriority priority); diff --git a/base/threading/platform_thread_android.cc b/base/threading/platform_thread_android.cc new file mode 100644 index 0000000..2802635 --- /dev/null +++ b/base/threading/platform_thread_android.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/threading/platform_thread.h" + +#include <errno.h> +#include <sys/resource.h> + +#include "base/android/jni_android.h" +#include "base/android/thread_utils.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/threading/thread_id_name_manager.h" +#include "base/tracked_objects.h" +#include "jni/ThreadUtils_jni.h" + +namespace base { + +namespace { +int ThreadNiceValue(ThreadPriority priority) { + // These nice values are taken from Android, which uses nice + // values like linux, but defines some preset nice values. + // Process.THREAD_PRIORITY_AUDIO = -16 + // Process.THREAD_PRIORITY_BACKGROUND = 10 + // Process.THREAD_PRIORITY_DEFAULT = 0; + // Process.THREAD_PRIORITY_DISPLAY = -4; + // Process.THREAD_PRIORITY_FOREGROUND = -2; + // Process.THREAD_PRIORITY_LESS_FAVORABLE = 1; + // Process.THREAD_PRIORITY_LOWEST = 19; + // Process.THREAD_PRIORITY_MORE_FAVORABLE = -1; + // Process.THREAD_PRIORITY_URGENT_AUDIO = -19; + // Process.THREAD_PRIORITY_URGENT_DISPLAY = -8; + // We use -6 for display, but we may want to split this + // into urgent (-8) and non-urgent (-4). + static const int threadPriorityAudio = -16; + static const int threadPriorityBackground = 10; + static const int threadPriorityDefault = 0; + static const int threadPriorityDisplay = -6; + switch (priority) { + case kThreadPriority_RealtimeAudio: + return threadPriorityAudio; + case kThreadPriority_Background: + return threadPriorityBackground; + case kThreadPriority_Normal: + return threadPriorityDefault; + case kThreadPriority_Display: + return threadPriorityDisplay; + default: + NOTREACHED() << "Unknown priority."; + return 0; + } +} +} // namespace + +//static +void PlatformThread::SetThreadPriority(PlatformThreadHandle handle, + ThreadPriority priority) { + // On Android, we set the Audio priority through JNI as Audio priority + // will also allow the process to run while it is backgrounded. + if (priority == kThreadPriority_RealtimeAudio) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_ThreadUtils_setThreadPriorityAudio(env, PlatformThread::CurrentId()); + return; + } + + // setpriority(2) will set a thread's priority if it is passed a tid as + // the 'process identifier', not affecting the rest of the threads in the + // process. Setting this priority will only succeed if the user has been + // granted permission to adjust nice values on the system. + DCHECK_NE(handle.id_, kInvalidThreadId); + int kNiceSetting = ThreadNiceValue(priority); + if (setpriority(PRIO_PROCESS, handle.id_, kNiceSetting)) + LOG(ERROR) << "Failed to set nice value of thread to " << kNiceSetting; +} + +void PlatformThread::SetName(const char* name) { + ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); + tracked_objects::ThreadData::InitializeThreadContext(name); +} + + +void InitThreading() { +} + +void InitOnThread() { + // Threads on linux/android may inherit their priority from the thread + // where they were created. This sets all new threads to the default. + PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(), + kThreadPriority_Normal); +} + +void TerminateOnThread() { + base::android::DetachFromVM(); +} + +size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) { + return 0; +} + +bool RegisterThreadUtils(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace base diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc new file mode 100644 index 0000000..42e12c7 --- /dev/null +++ b/base/threading/platform_thread_linux.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/threading/platform_thread.h" + +#include <errno.h> +#include <sched.h> + +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/safe_strerror_posix.h" +#include "base/threading/thread_id_name_manager.h" +#include "base/threading/thread_restrictions.h" +#include "base/tracked_objects.h" + +#if defined(OS_LINUX) +#include <sys/prctl.h> +#include <sys/resource.h> +#include <sys/syscall.h> +#include <sys/time.h> +#include <unistd.h> +#endif + +namespace base { + +namespace { +int ThreadNiceValue(ThreadPriority priority) { + static const int threadPriorityAudio = -10; + static const int threadPriorityBackground = 10; + static const int threadPriorityDefault = 0; + static const int threadPriorityDisplay = -6; + switch (priority) { + case kThreadPriority_RealtimeAudio: + return threadPriorityAudio; + case kThreadPriority_Background: + return threadPriorityBackground; + case kThreadPriority_Normal: + return threadPriorityDefault; + case kThreadPriority_Display: + return threadPriorityDisplay; + default: + NOTREACHED() << "Unknown priority."; + return 0; + } +} +} // namespace + +// static +void PlatformThread::SetName(const char* name) { + ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); + tracked_objects::ThreadData::InitializeThreadContext(name); + +#ifndef OS_NACL + // On linux we can get the thread names to show up in the debugger by setting + // the process name for the LWP. We don't want to do this for the main + // thread because that would rename the process, causing tools like killall + // to stop working. + if (PlatformThread::CurrentId() == getpid()) + return; + + // http://0pointer.de/blog/projects/name-your-threads.html + // Set the name for the LWP (which gets truncated to 15 characters). + // Note that glibc also has a 'pthread_setname_np' api, but it may not be + // available everywhere and it's only benefit over using prctl directly is + // that it can set the name of threads other than the current thread. + int err = prctl(PR_SET_NAME, name); + // We expect EPERM failures in sandboxed processes, just ignore those. + if (err < 0 && errno != EPERM) + DPLOG(ERROR) << "prctl(PR_SET_NAME)"; +#endif +} + +// static +void PlatformThread::SetThreadPriority(PlatformThreadHandle handle, + ThreadPriority priority) { +#ifndef OS_NACL + // setpriority(2) will set a thread's priority if it is passed a tid as + // the 'process identifier', not affecting the rest of the threads in the + // process. Setting this priority will only succeed if the user has been + // granted permission to adjust nice values on the system. + DCHECK_NE(handle.id_, kInvalidThreadId); + int kNiceSetting = ThreadNiceValue(priority); + if (setpriority(PRIO_PROCESS, handle.id_, kNiceSetting)) + LOG(ERROR) << "Failed to set nice value of thread to " << kNiceSetting; +#endif +} + +void InitThreading() { +} + +void InitOnThread() { +} + +void TerminateOnThread() { +} + +size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) { + return 0; +} + +} // namespace base diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm index 48041a0..d81a286 100644 --- a/base/threading/platform_thread_mac.mm +++ b/base/threading/platform_thread_mac.mm @@ -5,10 +5,12 @@ #include "base/threading/platform_thread.h" #import <Foundation/Foundation.h> +#include <algorithm> #include <dlfcn.h> #include <mach/mach.h> #include <mach/mach_time.h> #include <mach/thread_policy.h> +#include <sys/resource.h> #include "base/lazy_instance.h" #include "base/logging.h" @@ -163,7 +165,7 @@ void SetPriorityRealtimeAudio(mach_port_t mach_thread_id) { void PlatformThread::SetThreadPriority(PlatformThreadHandle handle, ThreadPriority priority) { // Convert from pthread_t to mach thread identifier. - mach_port_t mach_thread_id = pthread_mach_thread_np(handle); + mach_port_t mach_thread_id = pthread_mach_thread_np(handle.handle_); switch (priority) { case kThreadPriority_Normal: @@ -172,7 +174,51 @@ void PlatformThread::SetThreadPriority(PlatformThreadHandle handle, case kThreadPriority_RealtimeAudio: SetPriorityRealtimeAudio(mach_thread_id); break; + default: + NOTREACHED() << "Unknown priority."; + break; + } +} + +size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) { +#if defined(OS_IOS) + return 0; +#else + // The Mac OS X default for a pthread stack size is 512kB. + // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses + // DEFAULT_STACK_SIZE for this purpose. + // + // 512kB isn't quite generous enough for some deeply recursive threads that + // otherwise request the default stack size by specifying 0. Here, adopt + // glibc's behavior as on Linux, which is to use the current stack size + // limit (ulimit -s) as the default stack size. See + // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To + // avoid setting the limit below the Mac OS X default or the minimum usable + // stack size, these values are also considered. If any of these values + // can't be determined, or if stack size is unlimited (ulimit -s unlimited), + // stack_size is left at 0 to get the system default. + // + // Mac OS X normally only applies ulimit -s to the main thread stack. On + // contemporary OS X and Linux systems alike, this value is generally 8MB + // or in that neighborhood. + size_t default_stack_size = 0; + struct rlimit stack_rlimit; + if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 && + getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 && + stack_rlimit.rlim_cur != RLIM_INFINITY) { + default_stack_size = + std::max(std::max(default_stack_size, + static_cast<size_t>(PTHREAD_STACK_MIN)), + static_cast<size_t>(stack_rlimit.rlim_cur)); } + return default_stack_size; +#endif +} + +void InitOnThread() { +} + +void TerminateOnThread() { } } // namespace base diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc index 43e58b7..b1c0e9d 100644 --- a/base/threading/platform_thread_posix.cc +++ b/base/threading/platform_thread_posix.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/safe_strerror_posix.h" +#include "base/synchronization/waitable_event.h" #include "base/threading/thread_id_name_manager.h" #include "base/threading/thread_restrictions.h" #include "base/tracked_objects.h" @@ -28,74 +29,53 @@ #include <unistd.h> #endif -#if defined(OS_ANDROID) -#include <sys/resource.h> -#include "base/android/thread_utils.h" -#include "jni/ThreadUtils_jni.h" -#endif - namespace base { -#if defined(OS_MACOSX) void InitThreading(); -#endif +void InitOnThread(); +void TerminateOnThread(); +size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes); namespace { struct ThreadParams { + ThreadParams() + : delegate(NULL), + joinable(false), + priority(kThreadPriority_Normal), + handle(NULL), + handle_set(false, false) { + } + PlatformThread::Delegate* delegate; bool joinable; ThreadPriority priority; + PlatformThreadHandle* handle; + WaitableEvent handle_set; }; -void SetCurrentThreadPriority(ThreadPriority priority) { -#if defined(OS_LINUX) || defined(OS_ANDROID) - switch (priority) { - case kThreadPriority_Normal: - NOTREACHED() << "Don't reset priority as not all processes can."; - break; - case kThreadPriority_RealtimeAudio: -#if defined(OS_LINUX) - const int kNiceSetting = -10; - // Linux isn't posix compliant with setpriority(2), it will set a thread - // priority if it is passed a tid, not affecting the rest of the threads - // in the process. Setting this priority will only succeed if the user - // has been granted permission to adjust nice values on the system. - if (setpriority(PRIO_PROCESS, PlatformThread::CurrentId(), kNiceSetting)) - DVLOG(1) << "Failed to set nice value of thread to " << kNiceSetting; -#elif defined(OS_ANDROID) - JNIEnv* env = base::android::AttachCurrentThread(); - Java_ThreadUtils_setThreadPriorityAudio(env, PlatformThread::CurrentId()); -#endif // defined(OS_LINUX) - break; - } -#else // !defined(OS_LINUX) && !defined(OS_ANDROID) - PlatformThread::SetThreadPriority(pthread_self(), priority); -#endif -} - void* ThreadFunc(void* params) { -#if defined(OS_ANDROID) - // Threads on linux/android may inherit their priority from the thread - // where they were created. This sets all threads to the default. - // TODO(epenner): Move thread priorities to base. (crbug.com/170549) - if (setpriority(PRIO_PROCESS, PlatformThread::CurrentId(), 0)) - DVLOG(1) << "Failed to reset initial thread nice value to zero."; -#endif + base::InitOnThread(); ThreadParams* thread_params = static_cast<ThreadParams*>(params); + PlatformThread::Delegate* delegate = thread_params->delegate; if (!thread_params->joinable) base::ThreadRestrictions::SetSingletonAllowed(false); - // If there is a non-default priority for this thread, set it now. - if (thread_params->priority != kThreadPriority_Normal) - SetCurrentThreadPriority(thread_params->priority); + if (thread_params->priority != kThreadPriority_Normal) { + PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(), + thread_params->priority); + } + + // Stash the id in the handle so the calling thread has a complete + // handle, and unblock the parent thread. + *(thread_params->handle) = PlatformThreadHandle(pthread_self(), + PlatformThread::CurrentId()); + thread_params->handle_set.Signal(); - delete thread_params; delegate->ThreadMain(); -#if defined(OS_ANDROID) - base::android::DetachFromVM(); -#endif + + base::TerminateOnThread(); return NULL; } @@ -103,60 +83,36 @@ bool CreateThread(size_t stack_size, bool joinable, PlatformThread::Delegate* delegate, PlatformThreadHandle* thread_handle, ThreadPriority priority) { -#if defined(OS_MACOSX) base::InitThreading(); -#endif // OS_MACOSX bool success = false; pthread_attr_t attributes; pthread_attr_init(&attributes); - // Pthreads are joinable by default, so only specify the detached attribute if - // the thread should be non-joinable. + // Pthreads are joinable by default, so only specify the detached + // attribute if the thread should be non-joinable. if (!joinable) { pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); } -#if defined(OS_MACOSX) && !defined(OS_IOS) - // The Mac OS X default for a pthread stack size is 512kB. - // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses - // DEFAULT_STACK_SIZE for this purpose. - // - // 512kB isn't quite generous enough for some deeply recursive threads that - // otherwise request the default stack size by specifying 0. Here, adopt - // glibc's behavior as on Linux, which is to use the current stack size - // limit (ulimit -s) as the default stack size. See - // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To - // avoid setting the limit below the Mac OS X default or the minimum usable - // stack size, these values are also considered. If any of these values - // can't be determined, or if stack size is unlimited (ulimit -s unlimited), - // stack_size is left at 0 to get the system default. - // - // Mac OS X normally only applies ulimit -s to the main thread stack. On - // contemporary OS X and Linux systems alike, this value is generally 8MB - // or in that neighborhood. - if (stack_size == 0) { - size_t default_stack_size; - struct rlimit stack_rlimit; - if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 && - getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 && - stack_rlimit.rlim_cur != RLIM_INFINITY) { - stack_size = std::max(std::max(default_stack_size, - static_cast<size_t>(PTHREAD_STACK_MIN)), - static_cast<size_t>(stack_rlimit.rlim_cur)); - } - } -#endif // OS_MACOSX && !OS_IOS + // Get a better default if available. + if (stack_size == 0) + stack_size = base::GetDefaultThreadStackSize(attributes); if (stack_size > 0) pthread_attr_setstacksize(&attributes, stack_size); - ThreadParams* params = new ThreadParams; - params->delegate = delegate; - params->joinable = joinable; - params->priority = priority; - - int err = pthread_create(thread_handle, &attributes, ThreadFunc, params); + ThreadParams params; + params.delegate = delegate; + params.joinable = joinable; + params.priority = priority; + params.handle = thread_handle; + + pthread_t handle = 0; + int err = pthread_create(&handle, + &attributes, + ThreadFunc, + ¶ms); success = !err; if (!success) { errno = err; @@ -164,8 +120,13 @@ bool CreateThread(size_t stack_size, bool joinable, } pthread_attr_destroy(&attributes); - if (!success) - delete params; + + // Don't let this call complete until the thread id + // is set in the handle. + if (success) + params.handle_set.Wait(); + CHECK_EQ(handle, thread_handle->platform_handle()); + return success; } @@ -193,6 +154,11 @@ PlatformThreadId PlatformThread::CurrentId() { #endif } +//static +PlatformThreadHandle PlatformThread::CurrentHandle() { + return PlatformThreadHandle(pthread_self(), CurrentId()); +} + // static void PlatformThread::YieldCurrentThread() { sched_yield(); @@ -213,42 +179,6 @@ void PlatformThread::Sleep(TimeDelta duration) { sleep_time = remaining; } -#if defined(OS_LINUX) -// static -void PlatformThread::SetName(const char* name) { - ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); - tracked_objects::ThreadData::InitializeThreadContext(name); - - // On linux we can get the thread names to show up in the debugger by setting - // the process name for the LWP. We don't want to do this for the main - // thread because that would rename the process, causing tools like killall - // to stop working. - if (PlatformThread::CurrentId() == getpid()) - return; - - // http://0pointer.de/blog/projects/name-your-threads.html - // Set the name for the LWP (which gets truncated to 15 characters). - // Note that glibc also has a 'pthread_setname_np' api, but it may not be - // available everywhere and it's only benefit over using prctl directly is - // that it can set the name of threads other than the current thread. - int err = prctl(PR_SET_NAME, name); - // We expect EPERM failures in sandboxed processes, just ignore those. - if (err < 0 && errno != EPERM) - DPLOG(ERROR) << "prctl(PR_SET_NAME)"; -} -#elif defined(OS_MACOSX) -// Mac is implemented in platform_thread_mac.mm. -#else -// static -void PlatformThread::SetName(const char* name) { - ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); - tracked_objects::ThreadData::InitializeThreadContext(name); - - // (This should be relatively simple to implement for the BSDs; I - // just don't have one handy to test the code on.) -} -#endif // defined(OS_LINUX) - // static const char* PlatformThread::GetName() { return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); @@ -257,6 +187,7 @@ const char* PlatformThread::GetName() { // static bool PlatformThread::Create(size_t stack_size, Delegate* delegate, PlatformThreadHandle* thread_handle) { + base::ThreadRestrictions::ScopedAllowWait allow_wait; return CreateThread(stack_size, true /* joinable thread */, delegate, thread_handle, kThreadPriority_Normal); } @@ -265,6 +196,7 @@ bool PlatformThread::Create(size_t stack_size, Delegate* delegate, bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate, PlatformThreadHandle* thread_handle, ThreadPriority priority) { + base::ThreadRestrictions::ScopedAllowWait allow_wait; return CreateThread(stack_size, true, // joinable thread delegate, thread_handle, priority); } @@ -273,6 +205,7 @@ bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate, bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { PlatformThreadHandle unused; + base::ThreadRestrictions::ScopedAllowWait allow_wait; bool result = CreateThread(stack_size, false /* non-joinable thread */, delegate, &unused, kThreadPriority_Normal); return result; @@ -284,21 +217,7 @@ void PlatformThread::Join(PlatformThreadHandle thread_handle) { // the thread referred to by |thread_handle| may still be running long-lived / // blocking tasks. base::ThreadRestrictions::AssertIOAllowed(); - pthread_join(thread_handle, NULL); -} - -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) -// Mac OS X uses lower-level mach APIs and Android uses Java APIs. -// static -void PlatformThread::SetThreadPriority(PlatformThreadHandle, ThreadPriority) { - // TODO(crogers): Implement, see http://crbug.com/116172 -} -#endif - -#if defined(OS_ANDROID) -bool RegisterThreadUtils(JNIEnv* env) { - return RegisterNativesImpl(env); + pthread_join(thread_handle.handle_, NULL); } -#endif // defined(OS_ANDROID) } // namespace base diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc index e37709a..59f29da 100644 --- a/base/threading/platform_thread_unittest.cc +++ b/base/threading/platform_thread_unittest.cc @@ -29,7 +29,7 @@ class TrivialThread : public PlatformThread::Delegate { TEST(PlatformThreadTest, Trivial) { TrivialThread thread; - PlatformThreadHandle handle = kNullThreadHandle; + PlatformThreadHandle handle; ASSERT_FALSE(thread.did_run()); ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); @@ -80,7 +80,7 @@ TEST(PlatformThreadTest, Function) { PlatformThreadId main_thread_id = PlatformThread::CurrentId(); FunctionTestThread thread; - PlatformThreadHandle handle = kNullThreadHandle; + PlatformThreadHandle handle; ASSERT_FALSE(thread.did_run()); ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc index 9e877b3..904f2b4 100644 --- a/base/threading/platform_thread_win.cc +++ b/base/threading/platform_thread_win.cc @@ -64,7 +64,6 @@ DWORD __stdcall ThreadFunc(void* params) { bool CreateThreadInternal(size_t stack_size, PlatformThread::Delegate* delegate, PlatformThreadHandle* out_thread_handle) { - PlatformThreadHandle thread_handle; unsigned int flags = 0; if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) { flags = STACK_SIZE_PARAM_IS_A_RESERVATION; @@ -81,7 +80,7 @@ bool CreateThreadInternal(size_t stack_size, // have to work running on CreateThread() threads anyway, since we run code // on the Windows thread pool, etc. For some background on the difference: // http://www.microsoft.com/msj/1099/win32/win321099.aspx - thread_handle = CreateThread( + void* thread_handle = CreateThread( NULL, stack_size, ThreadFunc, params, flags, NULL); if (!thread_handle) { delete params; @@ -89,7 +88,7 @@ bool CreateThreadInternal(size_t stack_size, } if (out_thread_handle) - *out_thread_handle = thread_handle; + *out_thread_handle = PlatformThreadHandle(thread_handle); else CloseHandle(thread_handle); return true; @@ -103,6 +102,12 @@ PlatformThreadId PlatformThread::CurrentId() { } // static +PlatformThreadHandle PlatformThread::CurrentHandle() { + NOTIMPLEMENTED(); // See OpenThread() + return PlatformThreadHandle(); +} + +// static void PlatformThread::YieldCurrentThread() { ::Sleep(0); } @@ -164,7 +169,7 @@ bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { // static void PlatformThread::Join(PlatformThreadHandle thread_handle) { - DCHECK(thread_handle); + DCHECK(thread_handle.handle_); // TODO(willchan): Enable this check once I can get it to work for Windows // shutdown. // Joining another thread may block the current thread for a long time, since @@ -176,17 +181,17 @@ void PlatformThread::Join(PlatformThreadHandle thread_handle) { // Wait for the thread to exit. It should already have terminated but make // sure this assumption is valid. - DWORD result = WaitForSingleObject(thread_handle, INFINITE); + DWORD result = WaitForSingleObject(thread_handle.handle_, INFINITE); if (result != WAIT_OBJECT_0) { // Debug info for bug 127931. DWORD error = GetLastError(); debug::Alias(&error); debug::Alias(&result); - debug::Alias(&thread_handle); + debug::Alias(&thread_handle.handle_); CHECK(false); } - CloseHandle(thread_handle); + CloseHandle(thread_handle.handle_); } // static @@ -194,10 +199,13 @@ void PlatformThread::SetThreadPriority(PlatformThreadHandle handle, ThreadPriority priority) { switch (priority) { case kThreadPriority_Normal: - ::SetThreadPriority(handle, THREAD_PRIORITY_NORMAL); + ::SetThreadPriority(handle.handle_, THREAD_PRIORITY_NORMAL); break; case kThreadPriority_RealtimeAudio: - ::SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL); + ::SetThreadPriority(handle.handle_, THREAD_PRIORITY_TIME_CRITICAL); + break; + default: + NOTREACHED() << "Unknown priority."; break; } } diff --git a/base/threading/thread.cc b/base/threading/thread.cc index 35e88a7..8b3dc2b 100644 --- a/base/threading/thread.cc +++ b/base/threading/thread.cc @@ -148,6 +148,13 @@ bool Thread::IsRunning() const { return running_; } +void Thread::SetPriority(ThreadPriority priority) { + // The thread must be started (and id known) for this to be + // compatible with all platforms. + DCHECK_NE(thread_id_, kInvalidThreadId); + PlatformThread::SetThreadPriority(thread_, priority); +} + void Thread::Run(MessageLoop* message_loop) { message_loop->Run(); } diff --git a/base/threading/thread.h b/base/threading/thread.h index cf1a86d..15f73a0 100644 --- a/base/threading/thread.h +++ b/base/threading/thread.h @@ -142,6 +142,9 @@ class BASE_EXPORT Thread : PlatformThread::Delegate { // Returns true if the thread has been started, and not yet stopped. bool IsRunning() const; + // Sets the thread priority. The thread must already be started. + void SetPriority(ThreadPriority priority); + protected: // Called just prior to starting the message loop virtual void Init() {} diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h index 51cfa27..5abc8dc9 100644 --- a/base/threading/thread_restrictions.h +++ b/base/threading/thread_restrictions.h @@ -182,6 +182,7 @@ class BASE_EXPORT ThreadRestrictions { friend class SimpleThread; friend class Thread; friend class ThreadTestHelper; + friend class PlatformThread; // END ALLOWED USAGE. // BEGIN USAGE THAT NEEDS TO BE FIXED. diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc index c287abb..656d517 100644 --- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc +++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc @@ -79,7 +79,7 @@ class DeadlockCheckerObserver { // Check whether |provider_| holds its lock. For this, we need a // separate thread. DeadlockCheckerThread thread(provider_); - base::PlatformThreadHandle handle = base::kNullThreadHandle; + base::PlatformThreadHandle handle; ASSERT_TRUE(base::PlatformThread::Create(0, &thread, &handle)); base::PlatformThread::Join(handle); notification_received_ = true; diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc index 13cb4ca..6c91282 100644 --- a/chrome/browser/printing/print_job.cc +++ b/chrome/browser/printing/print_job.cc @@ -331,7 +331,7 @@ void PrintJob::ControlledWorkerShutdown() { // - We don't want to run tasks while the thread is quitting. // - We want this code path to wait on the thread to quit before continuing. MSG msg; - HANDLE thread_handle = worker_->thread_handle(); + HANDLE thread_handle = worker_->thread_handle().platform_handle(); for (; thread_handle;) { // Note that we don't do any kind of message prioritization since we don't // execute any pending task or timer. diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h index e903268..150a778 100644 --- a/chrome_frame/chrome_frame_automation.h +++ b/chrome_frame/chrome_frame_automation.h @@ -226,7 +226,8 @@ class AutomationProxyCacheEntry DWORD WaitForThread(DWORD timeout) { // NOLINT DCHECK(thread_.get()); - return ::WaitForSingleObject(thread_->thread_handle(), timeout); + return ::WaitForSingleObject(thread_->thread_handle().platform_handle(), + timeout); } bool IsSameProfile(const std::wstring& name) const { diff --git a/content/renderer/media/webrtc_local_audio_track_unittest.cc b/content/renderer/media/webrtc_local_audio_track_unittest.cc index 7e2f473..3d11fae 100644 --- a/content/renderer/media/webrtc_local_audio_track_unittest.cc +++ b/content/renderer/media/webrtc_local_audio_track_unittest.cc @@ -30,13 +30,13 @@ class FakeAudioThread : public base::PlatformThread::Delegate { public: explicit FakeAudioThread(const scoped_refptr<WebRtcAudioCapturer>& capturer) : capturer_(capturer), - thread_(base::kNullThreadHandle), + thread_(), closure_(false, false) { DCHECK(capturer); audio_bus_ = media::AudioBus::Create(capturer_->audio_parameters()); } - virtual ~FakeAudioThread() { DCHECK(!thread_); } + virtual ~FakeAudioThread() { DCHECK(thread_.is_null()); } // base::PlatformThread::Delegate: virtual void ThreadMain() OVERRIDE { @@ -57,13 +57,13 @@ class FakeAudioThread : public base::PlatformThread::Delegate { void Start() { base::PlatformThread::CreateWithPriority( 0, this, &thread_, base::kThreadPriority_RealtimeAudio); - CHECK(thread_ != base::kNullThreadHandle); + CHECK(!thread_.is_null()); } void Stop() { closure_.Signal(); base::PlatformThread::Join(thread_); - thread_ = base::kNullThreadHandle; + thread_ = base::PlatformThreadHandle(); } private: diff --git a/media/audio/audio_device_thread.cc b/media/audio/audio_device_thread.cc index 7583c9e..f68c045 100644 --- a/media/audio/audio_device_thread.cc +++ b/media/audio/audio_device_thread.cc @@ -94,31 +94,31 @@ bool AudioDeviceThread::IsStopped() { AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback, base::SyncSocket::Handle socket, const char* thread_name) - : thread_(base::kNullThreadHandle), + : thread_(), callback_(callback), socket_(socket), thread_name_(thread_name) { } AudioDeviceThread::Thread::~Thread() { - DCHECK_EQ(thread_, base::kNullThreadHandle) << "Stop wasn't called"; + DCHECK(thread_.is_null()); } void AudioDeviceThread::Thread::Start() { base::AutoLock auto_lock(callback_lock_); - DCHECK_EQ(thread_, base::kNullThreadHandle); + DCHECK(thread_.is_null()); // This reference will be released when the thread exists. AddRef(); PlatformThread::CreateWithPriority(0, this, &thread_, base::kThreadPriority_RealtimeAudio); - CHECK(thread_ != base::kNullThreadHandle); + CHECK(!thread_.is_null()); } void AudioDeviceThread::Thread::Stop(base::MessageLoop* loop_for_join) { socket_.Shutdown(); - base::PlatformThreadHandle thread = base::kNullThreadHandle; + base::PlatformThreadHandle thread = base::PlatformThreadHandle(); { // NOLINT base::AutoLock auto_lock(callback_lock_); @@ -126,7 +126,7 @@ void AudioDeviceThread::Thread::Stop(base::MessageLoop* loop_for_join) { std::swap(thread, thread_); } - if (thread != base::kNullThreadHandle) { + if (!thread.is_null()) { if (loop_for_join) { loop_for_join->PostTask(FROM_HERE, base::Bind(&base::PlatformThread::Join, thread)); diff --git a/media/audio/cross_process_notification_win.cc b/media/audio/cross_process_notification_win.cc index 65e0e43..53bf0f4 100644 --- a/media/audio/cross_process_notification_win.cc +++ b/media/audio/cross_process_notification_win.cc @@ -121,7 +121,9 @@ class ExtraWaitThread : public base::PlatformThread::Delegate { &events_[MAXIMUM_WAIT_OBJECTS - 2], count_ - (MAXIMUM_WAIT_OBJECTS - 2), &thread_signaled_event)); - base::PlatformThread::Create(0, extra_wait_thread.get(), &next_thread); + base::PlatformThreadHandle handle; + base::PlatformThread::Create(0, extra_wait_thread.get(), &handle); + next_thread = handle.platform_handle(); event_count = MAXIMUM_WAIT_OBJECTS; events[MAXIMUM_WAIT_OBJECTS - 1] = next_thread; @@ -140,7 +142,7 @@ class ExtraWaitThread : public base::PlatformThread::Delegate { // so on), we must wait for ours to exit before we can check the // propagated event offset. if (next_thread) { - base::PlatformThread::Join(next_thread); + base::PlatformThread::Join(base::PlatformThreadHandle(next_thread)); next_thread = NULL; } if (thread_signaled_event != -1) @@ -156,7 +158,7 @@ class ExtraWaitThread : public base::PlatformThread::Delegate { } if (next_thread) - base::PlatformThread::Join(next_thread); + base::PlatformThread::Join(base::PlatformThreadHandle(next_thread)); } private: @@ -232,7 +234,7 @@ int CrossProcessNotification::WaitMultiple(const Notifications& notifications, base::PlatformThread::Create(0, &wait_thread, &thread); HANDLE events[MAXIMUM_WAIT_OBJECTS]; std::copy(&handles[0], &handles[MAXIMUM_WAIT_OBJECTS - 1], &events[0]); - events[MAXIMUM_WAIT_OBJECTS - 1] = thread; + events[MAXIMUM_WAIT_OBJECTS - 1] = thread.platform_handle(); wait = ::WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, &events[0], FALSE, INFINITE); wait_failed = wait < WAIT_OBJECT_0 || diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc index f79e99d..84e48c4 100644 --- a/media/filters/video_renderer_base.cc +++ b/media/filters/video_renderer_base.cc @@ -35,7 +35,7 @@ VideoRendererBase::VideoRendererBase( received_end_of_stream_(false), frame_available_(&lock_), state_(kUninitialized), - thread_(base::kNullThreadHandle), + thread_(), pending_read_(false), drop_frames_(drop_frames), playback_rate_(0), @@ -48,7 +48,7 @@ VideoRendererBase::VideoRendererBase( VideoRendererBase::~VideoRendererBase() { base::AutoLock auto_lock(lock_); CHECK(state_ == kStopped || state_ == kUninitialized) << state_; - CHECK_EQ(thread_, base::kNullThreadHandle); + CHECK(thread_.is_null()); } void VideoRendererBase::Play(const base::Closure& callback) { @@ -100,15 +100,15 @@ void VideoRendererBase::Stop(const base::Closure& callback) { DoStopOrError_Locked(); // Clean up our thread if present. - base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle; - if (thread_ != base::kNullThreadHandle) { + base::PlatformThreadHandle thread_to_join = base::PlatformThreadHandle(); + if (!thread_.is_null()) { // Signal the thread since it's possible to get stopped with the video // thread waiting for a read to complete. frame_available_.Signal(); std::swap(thread_, thread_to_join); } - if (thread_to_join != base::kNullThreadHandle) { + if (!thread_to_join.is_null()) { base::AutoUnlock auto_unlock(lock_); base::PlatformThread::Join(thread_to_join); } @@ -212,7 +212,7 @@ void VideoRendererBase::OnVideoFrameStreamInitialized(bool success, #if defined(OS_WIN) // Bump up our priority so our sleeping is more accurate. // TODO(scherkus): find out if this is necessary, but it seems to help. - ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL); + ::SetThreadPriority(thread_.platform_handle(), THREAD_PRIORITY_ABOVE_NORMAL); #endif // defined(OS_WIN) base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); } diff --git a/remoting/base/auto_thread.cc b/remoting/base/auto_thread.cc index d79af49..9890bc3 100644 --- a/remoting/base/auto_thread.cc +++ b/remoting/base/auto_thread.cc @@ -92,7 +92,7 @@ AutoThread::AutoThread(const char* name) #if defined(OS_WIN) com_init_type_(COM_INIT_NONE), #endif - thread_(0), + thread_(), name_(name), was_quit_properly_(false) { } @@ -102,7 +102,7 @@ AutoThread::AutoThread(const char* name, AutoThreadTaskRunner* joiner) #if defined(OS_WIN) com_init_type_(COM_INIT_NONE), #endif - thread_(0), + thread_(), name_(name), was_quit_properly_(false), joiner_(joiner) { @@ -112,14 +112,14 @@ AutoThread::~AutoThread() { DCHECK(!startup_data_); // Wait for the thread to exit. - if (thread_) { + if (!thread_.is_null()) { base::PlatformThread::Join(thread_); } } scoped_refptr<AutoThreadTaskRunner> AutoThread::StartWithType( base::MessageLoop::Type type) { - DCHECK(!thread_); + DCHECK(thread_.is_null()); #if defined(OS_WIN) DCHECK(com_init_type_ != COM_INIT_STA || type == base::MessageLoop::TYPE_UI); #endif |