diff options
Diffstat (limited to 'base/threading')
-rw-r--r-- | base/threading/platform_thread.h | 64 | ||||
-rw-r--r-- | base/threading/platform_thread_android.cc | 105 | ||||
-rw-r--r-- | base/threading/platform_thread_linux.cc | 103 | ||||
-rw-r--r-- | base/threading/platform_thread_mac.mm | 48 | ||||
-rw-r--r-- | base/threading/platform_thread_posix.cc | 201 | ||||
-rw-r--r-- | base/threading/platform_thread_unittest.cc | 4 | ||||
-rw-r--r-- | base/threading/platform_thread_win.cc | 26 | ||||
-rw-r--r-- | base/threading/thread.cc | 7 | ||||
-rw-r--r-- | base/threading/thread.h | 3 | ||||
-rw-r--r-- | base/threading/thread_restrictions.h | 1 |
10 files changed, 397 insertions, 165 deletions
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. |