summaryrefslogtreecommitdiffstats
path: root/base/threading
diff options
context:
space:
mode:
Diffstat (limited to 'base/threading')
-rw-r--r--base/threading/platform_thread.h64
-rw-r--r--base/threading/platform_thread_android.cc105
-rw-r--r--base/threading/platform_thread_linux.cc103
-rw-r--r--base/threading/platform_thread_mac.mm48
-rw-r--r--base/threading/platform_thread_posix.cc201
-rw-r--r--base/threading/platform_thread_unittest.cc4
-rw-r--r--base/threading/platform_thread_win.cc26
-rw-r--r--base/threading/thread.cc7
-rw-r--r--base/threading/thread.h3
-rw-r--r--base/threading/thread_restrictions.h1
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,
+ &params);
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.