Index: base/threading/platform_thread_posix.cc |
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc |
index 43e58b73375a0c3273422d9c28e10150d3835197..b1c0e9dba20d16bcdaafaa9a70fce3900a4efba8 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 |