diff options
Diffstat (limited to 'security/sandbox/chromium/base/threading')
18 files changed, 2577 insertions, 0 deletions
diff --git a/security/sandbox/chromium/base/threading/platform_thread.h b/security/sandbox/chromium/base/threading/platform_thread.h new file mode 100644 index 000000000..e2b09bcb5 --- /dev/null +++ b/security/sandbox/chromium/base/threading/platform_thread.h @@ -0,0 +1,199 @@ +// 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. + +// WARNING: You should *NOT* be using this class directly. PlatformThread is +// the low-level platform-specific abstraction to the OS's threading interface. +// You should instead be using a message-loop driven Thread, see thread.h. + +#ifndef BASE_THREADING_PLATFORM_THREAD_H_ +#define BASE_THREADING_PLATFORM_THREAD_H_ + +#include <stddef.h> + +#include "base/base_export.h" +#include "base/macros.h" +#include "base/time/time.h" +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <windows.h> +#elif defined(OS_POSIX) +#include <pthread.h> +#include <unistd.h> +#endif + +namespace base { + +// Used for logging. Always an integer value. +#if defined(OS_WIN) +typedef DWORD PlatformThreadId; +#elif defined(OS_POSIX) +typedef pid_t PlatformThreadId; +#endif + +// Used for thread checking and debugging. +// Meant to be as fast as possible. +// These are produced by PlatformThread::CurrentRef(), and used to later +// check if we are on the same thread or not by using ==. These are safe +// to copy between threads, but can't be copied to another process as they +// have no meaning there. Also, the internal identifier can be re-used +// after a thread dies, so a PlatformThreadRef cannot be reliably used +// to distinguish a new thread from an old, dead thread. +class PlatformThreadRef { + public: +#if defined(OS_WIN) + typedef DWORD RefType; +#elif defined(OS_POSIX) + typedef pthread_t RefType; +#endif + PlatformThreadRef() + : id_(0) { + } + + explicit PlatformThreadRef(RefType id) + : id_(id) { + } + + bool operator==(PlatformThreadRef other) const { + return id_ == other.id_; + } + + bool is_null() const { + return id_ == 0; + } + private: + RefType id_; +}; + +// Used to operate on threads. +class PlatformThreadHandle { + public: +#if defined(OS_WIN) + typedef void* Handle; +#elif defined(OS_POSIX) + typedef pthread_t Handle; +#endif + + PlatformThreadHandle() : handle_(0) {} + + explicit PlatformThreadHandle(Handle handle) : handle_(handle) {} + + bool is_equal(const PlatformThreadHandle& other) const { + return handle_ == other.handle_; + } + + bool is_null() const { + return !handle_; + } + + Handle platform_handle() const { + return handle_; + } + + private: + Handle handle_; +}; + +const PlatformThreadId kInvalidThreadId(0); + +// Valid values for priority of Thread::Options and SimpleThread::Options, and +// SetCurrentThreadPriority(), listed in increasing order of importance. +enum class ThreadPriority { + // Suitable for threads that shouldn't disrupt high priority work. + BACKGROUND, + // Default priority level. + NORMAL, + // Suitable for threads which generate data for the display (at ~60Hz). + DISPLAY, + // Suitable for low-latency, glitch-resistant audio. + REALTIME_AUDIO, +}; + +// A namespace for low-level thread functions. +class BASE_EXPORT PlatformThread { + public: + // Implement this interface to run code on a background thread. Your + // ThreadMain method will be called on the newly created thread. + class BASE_EXPORT Delegate { + public: + virtual void ThreadMain() = 0; + + protected: + virtual ~Delegate() {} + }; + + // Gets the current thread id, which may be useful for logging purposes. + static PlatformThreadId CurrentId(); + + // Gets the current thread reference, which can be used to check if + // we're on the right thread quickly. + static PlatformThreadRef CurrentRef(); + + // Get the handle representing the current thread. On Windows, this is a + // pseudo handle constant which will always represent the thread using it and + // hence should not be shared with other threads nor be used to differentiate + // the current thread from another. + static PlatformThreadHandle CurrentHandle(); + + // Yield the current thread so another thread can be scheduled. + static void YieldCurrentThread(); + + // Sleeps for the specified duration. + static void Sleep(base::TimeDelta duration); + + // Sets the thread name visible to debuggers/tools. This has no effect + // otherwise. + static void SetName(const std::string& name); + + // Gets the thread name, if previously set by SetName. + static const char* GetName(); + + // Creates a new thread. The |stack_size| parameter can be 0 to indicate + // that the default stack size should be used. Upon success, + // |*thread_handle| will be assigned a handle to the newly created thread, + // and |delegate|'s ThreadMain method will be executed on the newly created + // thread. + // NOTE: When you are done with the thread handle, you must call Join to + // release system resources associated with the thread. You must ensure that + // the Delegate object outlives the thread. + static bool Create(size_t stack_size, + Delegate* delegate, + PlatformThreadHandle* thread_handle) { + return CreateWithPriority(stack_size, delegate, thread_handle, + ThreadPriority::NORMAL); + } + + // CreateWithPriority() does the same thing as Create() except the priority of + // the thread is set based on |priority|. + static bool CreateWithPriority(size_t stack_size, Delegate* delegate, + PlatformThreadHandle* thread_handle, + ThreadPriority priority); + + // CreateNonJoinable() does the same thing as Create() except the thread + // cannot be Join()'d. Therefore, it also does not output a + // PlatformThreadHandle. + static bool CreateNonJoinable(size_t stack_size, Delegate* delegate); + + // Joins with a thread created via the Create function. This function blocks + // the caller until the designated thread exits. This will invalidate + // |thread_handle|. + static void Join(PlatformThreadHandle thread_handle); + + // Toggles the current thread's priority at runtime. A thread may not be able + // to raise its priority back up after lowering it if the process does not + // have a proper permission, e.g. CAP_SYS_NICE on Linux. + // Since changing other threads' priority is not permitted in favor of + // security, this interface is restricted to change only the current thread + // priority (https://crbug.com/399473). + static void SetCurrentThreadPriority(ThreadPriority priority); + + static ThreadPriority GetCurrentThreadPriority(); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread); +}; + +} // namespace base + +#endif // BASE_THREADING_PLATFORM_THREAD_H_ diff --git a/security/sandbox/chromium/base/threading/platform_thread_internal_posix.cc b/security/sandbox/chromium/base/threading/platform_thread_internal_posix.cc new file mode 100644 index 000000000..9af02044f --- /dev/null +++ b/security/sandbox/chromium/base/threading/platform_thread_internal_posix.cc @@ -0,0 +1,35 @@ +// Copyright 2015 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_internal_posix.h" + +#include "base/logging.h" + +namespace base { + +namespace internal { + +int ThreadPriorityToNiceValue(ThreadPriority priority) { + for (const ThreadPriorityToNiceValuePair& pair : + kThreadPriorityToNiceValueMap) { + if (pair.priority == priority) + return pair.nice_value; + } + NOTREACHED() << "Unknown ThreadPriority"; + return 0; +} + +ThreadPriority NiceValueToThreadPriority(int nice_value) { + for (const ThreadPriorityToNiceValuePair& pair : + kThreadPriorityToNiceValueMap) { + if (pair.nice_value == nice_value) + return pair.priority; + } + NOTREACHED() << "Unknown nice value"; + return ThreadPriority::NORMAL; +} + +} // namespace internal + +} // namespace base diff --git a/security/sandbox/chromium/base/threading/platform_thread_internal_posix.h b/security/sandbox/chromium/base/threading/platform_thread_internal_posix.h new file mode 100644 index 000000000..05a8d1e26 --- /dev/null +++ b/security/sandbox/chromium/base/threading/platform_thread_internal_posix.h @@ -0,0 +1,43 @@ +// Copyright 2015 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. + +#ifndef BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_ +#define BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_ + +#include "base/threading/platform_thread.h" + +namespace base { + +namespace internal { + +struct ThreadPriorityToNiceValuePair { + ThreadPriority priority; + int nice_value; +}; +extern const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4]; + +// Returns the nice value matching |priority| based on the platform-specific +// implementation of kThreadPriorityToNiceValueMap. +int ThreadPriorityToNiceValue(ThreadPriority priority); + +// Returns the ThreadPrioirty matching |nice_value| based on the platform- +// specific implementation of kThreadPriorityToNiceValueMap. +ThreadPriority NiceValueToThreadPriority(int nice_value); + +// Allows platform specific tweaks to the generic POSIX solution for +// SetCurrentThreadPriority. Returns true if the platform-specific +// implementation handled this |priority| change, false if the generic +// implementation should instead proceed. +bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority); + +// Returns true if there is a platform-specific ThreadPriority set on the +// current thread (and returns the actual ThreadPriority via |priority|). +// Returns false otherwise, leaving |priority| untouched. +bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority); + +} // namespace internal + +} // namespace base + +#endif // BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_ diff --git a/security/sandbox/chromium/base/threading/platform_thread_linux.cc b/security/sandbox/chromium/base/threading/platform_thread_linux.cc new file mode 100644 index 000000000..4057ede94 --- /dev/null +++ b/security/sandbox/chromium/base/threading/platform_thread_linux.cc @@ -0,0 +1,120 @@ +// 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 <stddef.h> + +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/threading/platform_thread_internal_posix.h" +#include "base/threading/thread_id_name_manager.h" +#include "base/tracked_objects.h" +#include "build/build_config.h" + +#if !defined(OS_NACL) +#include <pthread.h> +#include <sys/prctl.h> +#include <sys/types.h> +#include <unistd.h> +#endif + +namespace base { + +namespace internal { + +namespace { +#if !defined(OS_NACL) +const struct sched_param kRealTimePrio = {8}; +const struct sched_param kResetPrio = {0}; +#endif +} // namespace + +const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = { + {ThreadPriority::BACKGROUND, 10}, + {ThreadPriority::NORMAL, 0}, + {ThreadPriority::DISPLAY, -6}, + {ThreadPriority::REALTIME_AUDIO, -10}, +}; + +bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) { +#if !defined(OS_NACL) + ThreadPriority current_priority; + if (priority != ThreadPriority::REALTIME_AUDIO && + GetCurrentThreadPriorityForPlatform(¤t_priority) && + current_priority == ThreadPriority::REALTIME_AUDIO) { + // If the pthread's round-robin scheduler is already enabled, and the new + // priority will use setpriority() instead, the pthread scheduler should be + // reset to use SCHED_OTHER so that setpriority() just works. + pthread_setschedparam(pthread_self(), SCHED_OTHER, &kResetPrio); + return false; + } + return priority == ThreadPriority::REALTIME_AUDIO && + pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0; +#else + return false; +#endif +} + +bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority) { +#if !defined(OS_NACL) + int maybe_sched_rr = 0; + struct sched_param maybe_realtime_prio = {0}; + if (pthread_getschedparam(pthread_self(), &maybe_sched_rr, + &maybe_realtime_prio) == 0 && + maybe_sched_rr == SCHED_RR && + maybe_realtime_prio.sched_priority == kRealTimePrio.sched_priority) { + *priority = ThreadPriority::REALTIME_AUDIO; + return true; + } +#endif + return false; +} + +} // namespace internal + +// static +void PlatformThread::SetName(const std::string& name) { + ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); + tracked_objects::ThreadData::InitializeThreadContext(name); + +#if !defined(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.c_str()); + // We expect EPERM failures in sandboxed processes, just ignore those. + if (err < 0 && errno != EPERM) + DPLOG(ERROR) << "prctl(PR_SET_NAME)"; +#endif // !defined(OS_NACL) +} + +void InitThreading() {} + +void InitOnThread() {} + +void TerminateOnThread() {} + +size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) { +#if !defined(THREAD_SANITIZER) + return 0; +#else + // ThreadSanitizer bloats the stack heavily. Evidence has been that the + // default stack size isn't enough for some browser tests. + return 2 * (1 << 23); // 2 times 8192K (the default stack size on Linux). +#endif +} + +} // namespace base diff --git a/security/sandbox/chromium/base/threading/platform_thread_posix.cc b/security/sandbox/chromium/base/threading/platform_thread_posix.cc new file mode 100644 index 000000000..39a007316 --- /dev/null +++ b/security/sandbox/chromium/base/threading/platform_thread_posix.cc @@ -0,0 +1,263 @@ +// 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 <pthread.h> +#include <sched.h> +#include <stddef.h> +#include <stdint.h> +#include <sys/resource.h> +#include <sys/time.h> + +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/platform_thread_internal_posix.h" +#include "base/threading/thread_id_name_manager.h" +#include "base/threading/thread_restrictions.h" +#include "build/build_config.h" + +#if defined(OS_LINUX) +#include <sys/syscall.h> +#elif defined(OS_ANDROID) +#include <sys/types.h> +#endif + +namespace base { + +void InitThreading(); +void InitOnThread(); +void TerminateOnThread(); +size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes); + +namespace { + +struct ThreadParams { + ThreadParams() + : delegate(NULL), joinable(false), priority(ThreadPriority::NORMAL) {} + + PlatformThread::Delegate* delegate; + bool joinable; + ThreadPriority priority; +}; + +void* ThreadFunc(void* params) { + base::InitOnThread(); + + PlatformThread::Delegate* delegate = nullptr; + + { + scoped_ptr<ThreadParams> thread_params(static_cast<ThreadParams*>(params)); + + delegate = thread_params->delegate; + if (!thread_params->joinable) + base::ThreadRestrictions::SetSingletonAllowed(false); + + if (thread_params->priority != ThreadPriority::NORMAL) + PlatformThread::SetCurrentThreadPriority(thread_params->priority); + } + + ThreadIdNameManager::GetInstance()->RegisterThread( + PlatformThread::CurrentHandle().platform_handle(), + PlatformThread::CurrentId()); + + delegate->ThreadMain(); + + ThreadIdNameManager::GetInstance()->RemoveName( + PlatformThread::CurrentHandle().platform_handle(), + PlatformThread::CurrentId()); + + base::TerminateOnThread(); + return NULL; +} + +bool CreateThread(size_t stack_size, + bool joinable, + PlatformThread::Delegate* delegate, + PlatformThreadHandle* thread_handle, + ThreadPriority priority) { + DCHECK(thread_handle); + base::InitThreading(); + + 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. + if (!joinable) + pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); + + // 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); + + scoped_ptr<ThreadParams> params(new ThreadParams); + params->delegate = delegate; + params->joinable = joinable; + params->priority = priority; + + pthread_t handle; + int err = pthread_create(&handle, &attributes, ThreadFunc, params.get()); + bool success = !err; + if (success) { + // ThreadParams should be deleted on the created thread after used. + ignore_result(params.release()); + } else { + // Value of |handle| is undefined if pthread_create fails. + handle = 0; + errno = err; + PLOG(ERROR) << "pthread_create"; + } + *thread_handle = PlatformThreadHandle(handle); + + pthread_attr_destroy(&attributes); + + return success; +} + +} // namespace + +// static +PlatformThreadId PlatformThread::CurrentId() { + // Pthreads doesn't have the concept of a thread ID, so we have to reach down + // into the kernel. +#if defined(OS_MACOSX) + return pthread_mach_thread_np(pthread_self()); +#elif defined(OS_LINUX) + return syscall(__NR_gettid); +#elif defined(OS_ANDROID) + return gettid(); +#elif defined(OS_SOLARIS) || defined(OS_QNX) + return pthread_self(); +#elif defined(OS_NACL) && defined(__GLIBC__) + return pthread_self(); +#elif defined(OS_NACL) && !defined(__GLIBC__) + // Pointers are 32-bits in NaCl. + return reinterpret_cast<int32_t>(pthread_self()); +#elif defined(OS_POSIX) + return reinterpret_cast<int64_t>(pthread_self()); +#endif +} + +// static +PlatformThreadRef PlatformThread::CurrentRef() { + return PlatformThreadRef(pthread_self()); +} + +// static +PlatformThreadHandle PlatformThread::CurrentHandle() { + return PlatformThreadHandle(pthread_self()); +} + +// static +void PlatformThread::YieldCurrentThread() { + sched_yield(); +} + +// static +void PlatformThread::Sleep(TimeDelta duration) { + struct timespec sleep_time, remaining; + + // Break the duration into seconds and nanoseconds. + // NOTE: TimeDelta's microseconds are int64s while timespec's + // nanoseconds are longs, so this unpacking must prevent overflow. + sleep_time.tv_sec = duration.InSeconds(); + duration -= TimeDelta::FromSeconds(sleep_time.tv_sec); + sleep_time.tv_nsec = duration.InMicroseconds() * 1000; // nanoseconds + + while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) + sleep_time = remaining; +} + +// static +const char* PlatformThread::GetName() { + return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); +} + +// static +bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate, + PlatformThreadHandle* thread_handle, + ThreadPriority priority) { + return CreateThread(stack_size, true, // joinable thread + delegate, thread_handle, priority); +} + +// static +bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { + PlatformThreadHandle unused; + + bool result = CreateThread(stack_size, false /* non-joinable thread */, + delegate, &unused, ThreadPriority::NORMAL); + return result; +} + +// static +void PlatformThread::Join(PlatformThreadHandle thread_handle) { + // Joining another thread may block the current thread for a long time, since + // the thread referred to by |thread_handle| may still be running long-lived / + // blocking tasks. + base::ThreadRestrictions::AssertIOAllowed(); + CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), NULL)); +} + +// Mac has its own Set/GetCurrentThreadPriority() implementations. +#if !defined(OS_MACOSX) + +// static +void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) { +#if defined(OS_NACL) + NOTIMPLEMENTED(); +#else + if (internal::SetCurrentThreadPriorityForPlatform(priority)) + return; + + // setpriority(2) should change the whole thread group's (i.e. process) + // priority. However, as stated in the bugs section of + // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current + // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread + // attribute". Also, 0 is prefered to the current thread id since it is + // equivalent but makes sandboxing easier (https://crbug.com/399473). + const int nice_setting = internal::ThreadPriorityToNiceValue(priority); + if (setpriority(PRIO_PROCESS, 0, nice_setting)) { + DVPLOG(1) << "Failed to set nice value of thread (" + << PlatformThread::CurrentId() << ") to " << nice_setting; + } +#endif // defined(OS_NACL) +} + +// static +ThreadPriority PlatformThread::GetCurrentThreadPriority() { +#if defined(OS_NACL) + NOTIMPLEMENTED(); + return ThreadPriority::NORMAL; +#else + // Mirrors SetCurrentThreadPriority()'s implementation. + ThreadPriority platform_specific_priority; + if (internal::GetCurrentThreadPriorityForPlatform( + &platform_specific_priority)) { + return platform_specific_priority; + } + + // Need to clear errno before calling getpriority(): + // http://man7.org/linux/man-pages/man2/getpriority.2.html + errno = 0; + int nice_value = getpriority(PRIO_PROCESS, 0); + if (errno != 0) { + DVPLOG(1) << "Failed to get nice value of thread (" + << PlatformThread::CurrentId() << ")"; + return ThreadPriority::NORMAL; + } + + return internal::NiceValueToThreadPriority(nice_value); +#endif // !defined(OS_NACL) +} + +#endif // !defined(OS_MACOSX) + +} // namespace base diff --git a/security/sandbox/chromium/base/threading/platform_thread_win.cc b/security/sandbox/chromium/base/threading/platform_thread_win.cc new file mode 100644 index 000000000..d5bd9bed0 --- /dev/null +++ b/security/sandbox/chromium/base/threading/platform_thread_win.cc @@ -0,0 +1,284 @@ +// 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 <stddef.h> + +#include "base/debug/alias.h" +#include "base/debug/profiler.h" +#include "base/logging.h" +#include "base/threading/thread_id_name_manager.h" +#include "base/threading/thread_restrictions.h" +#include "base/tracked_objects.h" +#include "base/win/scoped_handle.h" +#include "base/win/windows_version.h" + +namespace base { + +namespace { + +// The information on how to set the thread name comes from +// a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx +const DWORD kVCThreadNameException = 0x406D1388; + +typedef struct tagTHREADNAME_INFO { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; + +// This function has try handling, so it is separated out of its caller. +void SetNameInternal(PlatformThreadId thread_id, const char* name) { + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = thread_id; + info.dwFlags = 0; + + __try { + RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD), + reinterpret_cast<DWORD_PTR*>(&info)); + } __except(EXCEPTION_CONTINUE_EXECUTION) { + } +} + +struct ThreadParams { + PlatformThread::Delegate* delegate; + bool joinable; + ThreadPriority priority; +}; + +DWORD __stdcall ThreadFunc(void* params) { + ThreadParams* thread_params = static_cast<ThreadParams*>(params); + PlatformThread::Delegate* delegate = thread_params->delegate; + if (!thread_params->joinable) + base::ThreadRestrictions::SetSingletonAllowed(false); + + if (thread_params->priority != ThreadPriority::NORMAL) + PlatformThread::SetCurrentThreadPriority(thread_params->priority); + + // Retrieve a copy of the thread handle to use as the key in the + // thread name mapping. + PlatformThreadHandle::Handle platform_handle; + BOOL did_dup = DuplicateHandle(GetCurrentProcess(), + GetCurrentThread(), + GetCurrentProcess(), + &platform_handle, + 0, + FALSE, + DUPLICATE_SAME_ACCESS); + + win::ScopedHandle scoped_platform_handle; + + if (did_dup) { + scoped_platform_handle.Set(platform_handle); + ThreadIdNameManager::GetInstance()->RegisterThread( + scoped_platform_handle.Get(), + PlatformThread::CurrentId()); + } + + delete thread_params; + delegate->ThreadMain(); + + if (did_dup) { + ThreadIdNameManager::GetInstance()->RemoveName( + scoped_platform_handle.Get(), + PlatformThread::CurrentId()); + } + + return 0; +} + +// CreateThreadInternal() matches PlatformThread::CreateWithPriority(), except +// that |out_thread_handle| may be nullptr, in which case a non-joinable thread +// is created. +bool CreateThreadInternal(size_t stack_size, + PlatformThread::Delegate* delegate, + PlatformThreadHandle* out_thread_handle, + ThreadPriority priority) { + unsigned int flags = 0; + if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) { + flags = STACK_SIZE_PARAM_IS_A_RESERVATION; + } else { + stack_size = 0; + } + + ThreadParams* params = new ThreadParams; + params->delegate = delegate; + params->joinable = out_thread_handle != nullptr; + params->priority = priority; + + // Using CreateThread here vs _beginthreadex makes thread creation a bit + // faster and doesn't require the loader lock to be available. Our code will + // 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 + void* thread_handle = + ::CreateThread(nullptr, stack_size, ThreadFunc, params, flags, nullptr); + if (!thread_handle) { + delete params; + return false; + } + + if (out_thread_handle) + *out_thread_handle = PlatformThreadHandle(thread_handle); + else + CloseHandle(thread_handle); + return true; +} + +} // namespace + +// static +PlatformThreadId PlatformThread::CurrentId() { + return ::GetCurrentThreadId(); +} + +// static +PlatformThreadRef PlatformThread::CurrentRef() { + return PlatformThreadRef(::GetCurrentThreadId()); +} + +// static +PlatformThreadHandle PlatformThread::CurrentHandle() { + return PlatformThreadHandle(::GetCurrentThread()); +} + +// static +void PlatformThread::YieldCurrentThread() { + ::Sleep(0); +} + +// static +void PlatformThread::Sleep(TimeDelta duration) { + // When measured with a high resolution clock, Sleep() sometimes returns much + // too early. We may need to call it repeatedly to get the desired duration. + TimeTicks end = TimeTicks::Now() + duration; + for (TimeTicks now = TimeTicks::Now(); now < end; now = TimeTicks::Now()) + ::Sleep(static_cast<DWORD>((end - now).InMillisecondsRoundedUp())); +} + +// static +void PlatformThread::SetName(const std::string& name) { + ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); + + // On Windows only, we don't need to tell the profiler about the "BrokerEvent" + // thread, as it exists only in the chrome.exe image, and never spawns or runs + // tasks (items which could be profiled). This test avoids the notification, + // which would also (as a side effect) initialize the profiler in this unused + // context, including setting up thread local storage, etc. The performance + // impact is not terrible, but there is no reason to do initialize it. + if (name != "BrokerEvent") + tracked_objects::ThreadData::InitializeThreadContext(name); + + // The debugger needs to be around to catch the name in the exception. If + // there isn't a debugger, we are just needlessly throwing an exception. + // If this image file is instrumented, we raise the exception anyway + // to provide the profiler with human-readable thread names. + if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented()) + return; + + SetNameInternal(CurrentId(), name.c_str()); +} + +// static +const char* PlatformThread::GetName() { + return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); +} + +// static +bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate, + PlatformThreadHandle* thread_handle, + ThreadPriority priority) { + DCHECK(thread_handle); + return CreateThreadInternal(stack_size, delegate, thread_handle, priority); +} + +// static +bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { + return CreateThreadInternal(stack_size, delegate, nullptr, + ThreadPriority::NORMAL); +} + +// static +void PlatformThread::Join(PlatformThreadHandle thread_handle) { + DCHECK(thread_handle.platform_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 + // the thread referred to by |thread_handle| may still be running long-lived / + // blocking tasks. +#if 0 + base::ThreadRestrictions::AssertIOAllowed(); +#endif + + // Wait for the thread to exit. It should already have terminated but make + // sure this assumption is valid. + DWORD result = WaitForSingleObject(thread_handle.platform_handle(), INFINITE); + if (result != WAIT_OBJECT_0) { + // Debug info for bug 127931. + DWORD error = GetLastError(); + debug::Alias(&error); + debug::Alias(&result); + CHECK(false); + } + + CloseHandle(thread_handle.platform_handle()); +} + +// static +void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) { + int desired_priority = THREAD_PRIORITY_ERROR_RETURN; + switch (priority) { + case ThreadPriority::BACKGROUND: + desired_priority = THREAD_PRIORITY_LOWEST; + break; + case ThreadPriority::NORMAL: + desired_priority = THREAD_PRIORITY_NORMAL; + break; + case ThreadPriority::DISPLAY: + desired_priority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case ThreadPriority::REALTIME_AUDIO: + desired_priority = THREAD_PRIORITY_TIME_CRITICAL; + break; + default: + NOTREACHED() << "Unknown priority."; + break; + } + DCHECK_NE(desired_priority, THREAD_PRIORITY_ERROR_RETURN); + +#ifndef NDEBUG + const BOOL success = +#endif + ::SetThreadPriority(PlatformThread::CurrentHandle().platform_handle(), + desired_priority); + DPLOG_IF(ERROR, !success) << "Failed to set thread priority to " + << desired_priority; +} + +// static +ThreadPriority PlatformThread::GetCurrentThreadPriority() { + int priority = + ::GetThreadPriority(PlatformThread::CurrentHandle().platform_handle()); + switch (priority) { + case THREAD_PRIORITY_LOWEST: + return ThreadPriority::BACKGROUND; + case THREAD_PRIORITY_NORMAL: + return ThreadPriority::NORMAL; + case THREAD_PRIORITY_ABOVE_NORMAL: + return ThreadPriority::DISPLAY; + case THREAD_PRIORITY_TIME_CRITICAL: + return ThreadPriority::REALTIME_AUDIO; + case THREAD_PRIORITY_ERROR_RETURN: + DPCHECK(false) << "GetThreadPriority error"; // Falls through. + default: + NOTREACHED() << "Unexpected priority: " << priority; + return ThreadPriority::NORMAL; + } +} + +} // namespace base diff --git a/security/sandbox/chromium/base/threading/sequenced_worker_pool.h b/security/sandbox/chromium/base/threading/sequenced_worker_pool.h new file mode 100644 index 000000000..ba0e44421 --- /dev/null +++ b/security/sandbox/chromium/base/threading/sequenced_worker_pool.h @@ -0,0 +1,384 @@ +// 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. + +#ifndef BASE_THREADING_SEQUENCED_WORKER_POOL_H_ +#define BASE_THREADING_SEQUENCED_WORKER_POOL_H_ + +#include <stddef.h> + +#include <cstddef> +#include <string> + +#include "base/base_export.h" +#include "base/callback_forward.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/task_runner.h" + +namespace tracked_objects { +class Location; +} // namespace tracked_objects + +namespace base { + +class SingleThreadTaskRunner; + +template <class T> class DeleteHelper; + +class SequencedTaskRunner; + +// A worker thread pool that enforces ordering between sets of tasks. It also +// allows you to specify what should happen to your tasks on shutdown. +// +// To enforce ordering, get a unique sequence token from the pool and post all +// tasks you want to order with the token. All tasks with the same token are +// guaranteed to execute serially, though not necessarily on the same thread. +// This means that: +// +// - No two tasks with the same token will run at the same time. +// +// - Given two tasks T1 and T2 with the same token such that T2 will +// run after T1, then T2 will start after T1 is destroyed. +// +// - If T2 will run after T1, then all memory changes in T1 and T1's +// destruction will be visible to T2. +// +// Example: +// SequencedWorkerPool::SequenceToken token = +// SequencedWorkerPool::GetSequenceToken(); +// pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN, +// FROM_HERE, base::Bind(...)); +// pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN, +// FROM_HERE, base::Bind(...)); +// +// You can make named sequence tokens to make it easier to share a token +// across different components. +// +// You can also post tasks to the pool without ordering using PostWorkerTask. +// These will be executed in an unspecified order. The order of execution +// between tasks with different sequence tokens is also unspecified. +// +// This class may be leaked on shutdown to facilitate fast shutdown. The +// expected usage, however, is to call Shutdown(), which correctly accounts +// for CONTINUE_ON_SHUTDOWN behavior and is required for BLOCK_SHUTDOWN +// behavior. +// +// Implementation note: This does not use a base::WorkerPool since that does +// not enforce shutdown semantics or allow us to specify how many worker +// threads to run. For the typical use case of random background work, we don't +// necessarily want to be super aggressive about creating threads. +// +// Note that SequencedWorkerPool is RefCountedThreadSafe (inherited +// from TaskRunner). +// +// Test-only code should wrap this in a base::SequencedWorkerPoolOwner to avoid +// memory leaks. See http://crbug.com/273800 +class BASE_EXPORT SequencedWorkerPool : public TaskRunner { + public: + // Defines what should happen to a task posted to the worker pool on + // shutdown. + enum WorkerShutdown { + // Tasks posted with this mode which have not run at shutdown will be + // deleted rather than run, and any tasks with this mode running at + // shutdown will be ignored (the worker thread will not be joined). + // + // This option provides a nice way to post stuff you don't want blocking + // shutdown. For example, you might be doing a slow DNS lookup and if it's + // blocked on the OS, you may not want to stop shutdown, since the result + // doesn't really matter at that point. + // + // However, you need to be very careful what you do in your callback when + // you use this option. Since the thread will continue to run until the OS + // terminates the process, the app can be in the process of tearing down + // when you're running. This means any singletons or global objects you + // use may suddenly become invalid out from under you. For this reason, + // it's best to use this only for slow but simple operations like the DNS + // example. + CONTINUE_ON_SHUTDOWN, + + // Tasks posted with this mode that have not started executing at + // shutdown will be deleted rather than executed. However, any tasks that + // have already begun executing when shutdown is called will be allowed + // to continue, and will block shutdown until completion. + // + // Note: Because Shutdown() may block while these tasks are executing, + // care must be taken to ensure that they do not block on the thread that + // called Shutdown(), as this may lead to deadlock. + SKIP_ON_SHUTDOWN, + + // Tasks posted with this mode will block shutdown until they're + // executed. Since this can have significant performance implications, + // use sparingly. + // + // Generally, this should be used only for user data, for example, a task + // writing a preference file. + // + // If a task is posted during shutdown, it will not get run since the + // workers may already be stopped. In this case, the post operation will + // fail (return false) and the task will be deleted. + BLOCK_SHUTDOWN, + }; + + // Opaque identifier that defines sequencing of tasks posted to the worker + // pool. + class BASE_EXPORT SequenceToken { + public: + SequenceToken() : id_(0) {} + ~SequenceToken() {} + + bool Equals(const SequenceToken& other) const { + return id_ == other.id_; + } + + // Returns false if current thread is executing an unsequenced task. + bool IsValid() const { + return id_ != 0; + } + + // Returns a string representation of this token. This method should only be + // used for debugging. + std::string ToString() const; + + private: + friend class SequencedWorkerPool; + + explicit SequenceToken(int id) : id_(id) {} + + int id_; + }; + + // Allows tests to perform certain actions. + class TestingObserver { + public: + virtual ~TestingObserver() {} + virtual void OnHasWork() = 0; + virtual void WillWaitForShutdown() = 0; + virtual void OnDestruct() = 0; + }; + + // Gets the SequencedToken of the current thread. + // If current thread is not a SequencedWorkerPool worker thread or is running + // an unsequenced task, returns an invalid SequenceToken. + static SequenceToken GetSequenceTokenForCurrentThread(); + + // Gets a SequencedTaskRunner for the current thread. If the current thread is + // running an unsequenced task, a new SequenceToken will be generated and set, + // so that the returned SequencedTaskRunner is guaranteed to run tasks after + // the current task has finished running. + static scoped_refptr<SequencedTaskRunner> + GetSequencedTaskRunnerForCurrentThread(); + + // Returns a unique token that can be used to sequence tasks posted to + // PostSequencedWorkerTask(). Valid tokens are always nonzero. + // TODO(bauerb): Rename this to better differentiate from + // GetSequenceTokenForCurrentThread(). + static SequenceToken GetSequenceToken(); + + // Returns the SequencedWorkerPool that owns this thread, or null if the + // current thread is not a SequencedWorkerPool worker thread. + static scoped_refptr<SequencedWorkerPool> GetWorkerPoolForCurrentThread(); + + // When constructing a SequencedWorkerPool, there must be a + // ThreadTaskRunnerHandle on the current thread unless you plan to + // deliberately leak it. + + // Pass the maximum number of threads (they will be lazily created as needed) + // and a prefix for the thread name to aid in debugging. + SequencedWorkerPool(size_t max_threads, + const std::string& thread_name_prefix); + + // Like above, but with |observer| for testing. Does not take ownership of + // |observer|. + SequencedWorkerPool(size_t max_threads, + const std::string& thread_name_prefix, + TestingObserver* observer); + + // Returns the sequence token associated with the given name. Calling this + // function multiple times with the same string will always produce the + // same sequence token. If the name has not been used before, a new token + // will be created. + SequenceToken GetNamedSequenceToken(const std::string& name); + + // Returns a SequencedTaskRunner wrapper which posts to this + // SequencedWorkerPool using the given sequence token. Tasks with nonzero + // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay + // are posted with BLOCK_SHUTDOWN behavior. + scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunner( + SequenceToken token); + + // Returns a SequencedTaskRunner wrapper which posts to this + // SequencedWorkerPool using the given sequence token. Tasks with nonzero + // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay + // are posted with the given shutdown behavior. + scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunnerWithShutdownBehavior( + SequenceToken token, + WorkerShutdown shutdown_behavior); + + // Returns a TaskRunner wrapper which posts to this SequencedWorkerPool using + // the given shutdown behavior. Tasks with nonzero delay are posted with + // SKIP_ON_SHUTDOWN behavior and tasks with zero delay are posted with the + // given shutdown behavior. + scoped_refptr<TaskRunner> GetTaskRunnerWithShutdownBehavior( + WorkerShutdown shutdown_behavior); + + // Posts the given task for execution in the worker pool. Tasks posted with + // this function will execute in an unspecified order on a background thread. + // Returns true if the task was posted. If your tasks have ordering + // requirements, see PostSequencedWorkerTask(). + // + // This class will attempt to delete tasks that aren't run + // (non-block-shutdown semantics) but can't guarantee that this happens. If + // all worker threads are busy running CONTINUE_ON_SHUTDOWN tasks, there + // will be no workers available to delete these tasks. And there may be + // tasks with the same sequence token behind those CONTINUE_ON_SHUTDOWN + // tasks. Deleting those tasks before the previous one has completed could + // cause nondeterministic crashes because the task could be keeping some + // objects alive which do work in their destructor, which could voilate the + // assumptions of the running task. + // + // The task will be guaranteed to run to completion before shutdown + // (BLOCK_SHUTDOWN semantics). + // + // Returns true if the task was posted successfully. This may fail during + // shutdown regardless of the specified ShutdownBehavior. + bool PostWorkerTask(const tracked_objects::Location& from_here, + const Closure& task); + + // Same as PostWorkerTask but allows a delay to be specified (although doing + // so changes the shutdown behavior). The task will be run after the given + // delay has elapsed. + // + // If the delay is nonzero, the task won't be guaranteed to run to completion + // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs. + // If the delay is zero, this behaves exactly like PostWorkerTask, i.e. the + // task will be guaranteed to run to completion before shutdown + // (BLOCK_SHUTDOWN semantics). + bool PostDelayedWorkerTask(const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay); + + // Same as PostWorkerTask but allows specification of the shutdown behavior. + bool PostWorkerTaskWithShutdownBehavior( + const tracked_objects::Location& from_here, + const Closure& task, + WorkerShutdown shutdown_behavior); + + // Like PostWorkerTask above, but provides sequencing semantics. This means + // that tasks posted with the same sequence token (see GetSequenceToken()) + // are guaranteed to execute in order. This is useful in cases where you're + // doing operations that may depend on previous ones, like appending to a + // file. + // + // The task will be guaranteed to run to completion before shutdown + // (BLOCK_SHUTDOWN semantics). + // + // Returns true if the task was posted successfully. This may fail during + // shutdown regardless of the specified ShutdownBehavior. + bool PostSequencedWorkerTask(SequenceToken sequence_token, + const tracked_objects::Location& from_here, + const Closure& task); + + // Like PostSequencedWorkerTask above, but allows you to specify a named + // token, which saves an extra call to GetNamedSequenceToken. + bool PostNamedSequencedWorkerTask(const std::string& token_name, + const tracked_objects::Location& from_here, + const Closure& task); + + // Same as PostSequencedWorkerTask but allows a delay to be specified + // (although doing so changes the shutdown behavior). The task will be run + // after the given delay has elapsed. + // + // If the delay is nonzero, the task won't be guaranteed to run to completion + // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs. + // If the delay is zero, this behaves exactly like PostSequencedWorkerTask, + // i.e. the task will be guaranteed to run to completion before shutdown + // (BLOCK_SHUTDOWN semantics). + bool PostDelayedSequencedWorkerTask( + SequenceToken sequence_token, + const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay); + + // Same as PostSequencedWorkerTask but allows specification of the shutdown + // behavior. + bool PostSequencedWorkerTaskWithShutdownBehavior( + SequenceToken sequence_token, + const tracked_objects::Location& from_here, + const Closure& task, + WorkerShutdown shutdown_behavior); + + // TaskRunner implementation. Forwards to PostDelayedWorkerTask(). + bool PostDelayedTask(const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay) override; + bool RunsTasksOnCurrentThread() const override; + + // Returns true if the current thread is processing a task with the given + // sequence_token. + bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const; + + // Returns true if any thread is currently processing a task with the given + // sequence token. Should only be called with a valid sequence token. + bool IsRunningSequence(SequenceToken sequence_token) const; + + // Blocks until all pending tasks are complete. This should only be called in + // unit tests when you want to validate something that should have happened. + // This will not flush delayed tasks; delayed tasks get deleted. + // + // Note that calling this will not prevent other threads from posting work to + // the queue while the calling thread is waiting on Flush(). In this case, + // Flush will return only when there's no more work in the queue. Normally, + // this doesn't come up since in a test, all the work is being posted from + // the main thread. + void FlushForTesting(); + + // Spuriously signal that there is work to be done. + void SignalHasWorkForTesting(); + + // Implements the worker pool shutdown. This should be called during app + // shutdown, and will discard/join with appropriate tasks before returning. + // After this call, subsequent calls to post tasks will fail. + // + // Must be called from the same thread this object was constructed on. + void Shutdown() { Shutdown(0); } + + // A variant that allows an arbitrary number of new blocking tasks to be + // posted during shutdown. The tasks cannot be posted within the execution + // context of tasks whose shutdown behavior is not BLOCKING_SHUTDOWN. Once + // the limit is reached, subsequent calls to post task fail in all cases. + // Must be called from the same thread this object was constructed on. + void Shutdown(int max_new_blocking_tasks_after_shutdown); + + // Check if Shutdown was called for given threading pool. This method is used + // for aborting time consuming operation to avoid blocking shutdown. + // + // Can be called from any thread. + bool IsShutdownInProgress(); + + protected: + ~SequencedWorkerPool() override; + + void OnDestruct() const override; + + private: + friend class RefCountedThreadSafe<SequencedWorkerPool>; + friend class DeleteHelper<SequencedWorkerPool>; + + class Inner; + class Worker; + + const scoped_refptr<SingleThreadTaskRunner> constructor_task_runner_; + + // Avoid pulling in too many headers by putting (almost) everything + // into |inner_|. + const scoped_ptr<Inner> inner_; + + DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPool); +}; + +} // namespace base + +#endif // BASE_THREADING_SEQUENCED_WORKER_POOL_H_ diff --git a/security/sandbox/chromium/base/threading/thread_checker_impl.h b/security/sandbox/chromium/base/threading/thread_checker_impl.h new file mode 100644 index 000000000..c92e143db --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_checker_impl.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 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. + +#ifndef BASE_THREADING_THREAD_CHECKER_IMPL_H_ +#define BASE_THREADING_THREAD_CHECKER_IMPL_H_ + +#include "base/base_export.h" +#include "base/compiler_specific.h" +#include "base/synchronization/lock.h" +#include "base/threading/platform_thread.h" + +namespace base { + +// Real implementation of ThreadChecker, for use in debug mode, or +// for temporary use in release mode (e.g. to CHECK on a threading issue +// seen only in the wild). +// +// Note: You should almost always use the ThreadChecker class to get the +// right version for your build configuration. +class BASE_EXPORT ThreadCheckerImpl { + public: + ThreadCheckerImpl(); + ~ThreadCheckerImpl(); + + bool CalledOnValidThread() const WARN_UNUSED_RESULT; + + // Changes the thread that is checked for in CalledOnValidThread. This may + // be useful when an object may be created on one thread and then used + // exclusively on another thread. + void DetachFromThread(); + + private: + void EnsureThreadIdAssigned() const; + + mutable base::Lock lock_; + // This is mutable so that CalledOnValidThread can set it. + // It's guarded by |lock_|. + mutable PlatformThreadRef valid_thread_id_; +}; + +} // namespace base + +#endif // BASE_THREADING_THREAD_CHECKER_IMPL_H_ diff --git a/security/sandbox/chromium/base/threading/thread_collision_warner.cc b/security/sandbox/chromium/base/threading/thread_collision_warner.cc new file mode 100644 index 000000000..547e11ca6 --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_collision_warner.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2010 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/thread_collision_warner.h" + +#include "base/logging.h" +#include "base/threading/platform_thread.h" + +namespace base { + +void DCheckAsserter::warn() { + NOTREACHED() << "Thread Collision"; +} + +static subtle::Atomic32 CurrentThread() { + const PlatformThreadId current_thread_id = PlatformThread::CurrentId(); + // We need to get the thread id into an atomic data type. This might be a + // truncating conversion, but any loss-of-information just increases the + // chance of a fault negative, not a false positive. + const subtle::Atomic32 atomic_thread_id = + static_cast<subtle::Atomic32>(current_thread_id); + + return atomic_thread_id; +} + +void ThreadCollisionWarner::EnterSelf() { + // If the active thread is 0 then I'll write the current thread ID + // if two or more threads arrive here only one will succeed to + // write on valid_thread_id_ the current thread ID. + subtle::Atomic32 current_thread_id = CurrentThread(); + + int previous_value = subtle::NoBarrier_CompareAndSwap(&valid_thread_id_, + 0, + current_thread_id); + if (previous_value != 0 && previous_value != current_thread_id) { + // gotcha! a thread is trying to use the same class and that is + // not current thread. + asserter_->warn(); + } + + subtle::NoBarrier_AtomicIncrement(&counter_, 1); +} + +void ThreadCollisionWarner::Enter() { + subtle::Atomic32 current_thread_id = CurrentThread(); + + if (subtle::NoBarrier_CompareAndSwap(&valid_thread_id_, + 0, + current_thread_id) != 0) { + // gotcha! another thread is trying to use the same class. + asserter_->warn(); + } + + subtle::NoBarrier_AtomicIncrement(&counter_, 1); +} + +void ThreadCollisionWarner::Leave() { + if (subtle::Barrier_AtomicIncrement(&counter_, -1) == 0) { + subtle::NoBarrier_Store(&valid_thread_id_, 0); + } +} + +} // namespace base diff --git a/security/sandbox/chromium/base/threading/thread_collision_warner.h b/security/sandbox/chromium/base/threading/thread_collision_warner.h new file mode 100644 index 000000000..4699a910d --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_collision_warner.h @@ -0,0 +1,245 @@ +// 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. + +#ifndef BASE_THREADING_THREAD_COLLISION_WARNER_H_ +#define BASE_THREADING_THREAD_COLLISION_WARNER_H_ + +#include <memory> + +#include "base/atomicops.h" +#include "base/base_export.h" +#include "base/compiler_specific.h" +#include "base/macros.h" + +// A helper class alongside macros to be used to verify assumptions about thread +// safety of a class. +// +// Example: Queue implementation non thread-safe but still usable if clients +// are synchronized somehow. +// +// In this case the macro DFAKE_SCOPED_LOCK has to be +// used, it checks that if a thread is inside the push/pop then +// noone else is still inside the pop/push +// +// class NonThreadSafeQueue { +// public: +// ... +// void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... } +// int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... } +// ... +// private: +// DFAKE_MUTEX(push_pop_); +// }; +// +// +// Example: Queue implementation non thread-safe but still usable if clients +// are synchronized somehow, it calls a method to "protect" from +// a "protected" method +// +// In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK +// has to be used, it checks that if a thread is inside the push/pop +// then noone else is still inside the pop/push +// +// class NonThreadSafeQueue { +// public: +// void push(int) { +// DFAKE_SCOPED_LOCK(push_pop_); +// ... +// } +// int pop() { +// DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); +// bar(); +// ... +// } +// void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... } +// ... +// private: +// DFAKE_MUTEX(push_pop_); +// }; +// +// +// Example: Queue implementation not usable even if clients are synchronized, +// so only one thread in the class life cycle can use the two members +// push/pop. +// +// In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the +// specified +// critical section the first time a thread enters push or pop, from +// that time on only that thread is allowed to execute push or pop. +// +// class NonThreadSafeQueue { +// public: +// ... +// void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } +// int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } +// ... +// private: +// DFAKE_MUTEX(push_pop_); +// }; +// +// +// Example: Class that has to be contructed/destroyed on same thread, it has +// a "shareable" method (with external synchronization) and a not +// shareable method (even with external synchronization). +// +// In this case 3 Critical sections have to be defined +// +// class ExoticClass { +// public: +// ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } +// ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } +// +// void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... } +// void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } +// ... +// private: +// DFAKE_MUTEX(ctor_dtor_); +// DFAKE_MUTEX(shareable_section_); +// }; + + +#if !defined(NDEBUG) + +// Defines a class member that acts like a mutex. It is used only as a +// verification tool. +#define DFAKE_MUTEX(obj) \ + mutable base::ThreadCollisionWarner obj +// Asserts the call is never called simultaneously in two threads. Used at +// member function scope. +#define DFAKE_SCOPED_LOCK(obj) \ + base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj) +// Asserts the call is never called simultaneously in two threads. Used at +// member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks. +#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \ + base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj) +// Asserts the code is always executed in the same thread. +#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \ + base::ThreadCollisionWarner::Check check_##obj(&obj) + +#else + +#define DFAKE_MUTEX(obj) typedef void InternalFakeMutexType##obj +#define DFAKE_SCOPED_LOCK(obj) ((void)0) +#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) ((void)0) +#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) ((void)0) + +#endif + +namespace base { + +// The class ThreadCollisionWarner uses an Asserter to notify the collision +// AsserterBase is the interfaces and DCheckAsserter is the default asserter +// used. During the unit tests is used another class that doesn't "DCHECK" +// in case of collision (check thread_collision_warner_unittests.cc) +struct BASE_EXPORT AsserterBase { + virtual ~AsserterBase() {} + virtual void warn() = 0; +}; + +struct BASE_EXPORT DCheckAsserter : public AsserterBase { + ~DCheckAsserter() override {} + void warn() override; +}; + +class BASE_EXPORT ThreadCollisionWarner { + public: + // The parameter asserter is there only for test purpose + explicit ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter()) + : valid_thread_id_(0), + counter_(0), + asserter_(asserter) {} + + ~ThreadCollisionWarner() { + delete asserter_; + } + + // This class is meant to be used through the macro + // DFAKE_SCOPED_LOCK_THREAD_LOCKED + // it doesn't leave the critical section, as opposed to ScopedCheck, + // because the critical section being pinned is allowed to be used only + // from one thread + class BASE_EXPORT Check { + public: + explicit Check(ThreadCollisionWarner* warner) + : warner_(warner) { + warner_->EnterSelf(); + } + + ~Check() {} + + private: + ThreadCollisionWarner* warner_; + + DISALLOW_COPY_AND_ASSIGN(Check); + }; + + // This class is meant to be used through the macro + // DFAKE_SCOPED_LOCK + class BASE_EXPORT ScopedCheck { + public: + explicit ScopedCheck(ThreadCollisionWarner* warner) + : warner_(warner) { + warner_->Enter(); + } + + ~ScopedCheck() { + warner_->Leave(); + } + + private: + ThreadCollisionWarner* warner_; + + DISALLOW_COPY_AND_ASSIGN(ScopedCheck); + }; + + // This class is meant to be used through the macro + // DFAKE_SCOPED_RECURSIVE_LOCK + class BASE_EXPORT ScopedRecursiveCheck { + public: + explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner) + : warner_(warner) { + warner_->EnterSelf(); + } + + ~ScopedRecursiveCheck() { + warner_->Leave(); + } + + private: + ThreadCollisionWarner* warner_; + + DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck); + }; + + private: + // This method stores the current thread identifier and does a DCHECK + // if a another thread has already done it, it is safe if same thread + // calls this multiple time (recursion allowed). + void EnterSelf(); + + // Same as EnterSelf but recursion is not allowed. + void Enter(); + + // Removes the thread_id stored in order to allow other threads to + // call EnterSelf or Enter. + void Leave(); + + // This stores the thread id that is inside the critical section, if the + // value is 0 then no thread is inside. + volatile subtle::Atomic32 valid_thread_id_; + + // Counter to trace how many time a critical section was "pinned" + // (when allowed) in order to unpin it when counter_ reaches 0. + volatile subtle::Atomic32 counter_; + + // Here only for class unit tests purpose, during the test I need to not + // DCHECK but notify the collision with something else. + AsserterBase* asserter_; + + DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner); +}; + +} // namespace base + +#endif // BASE_THREADING_THREAD_COLLISION_WARNER_H_ diff --git a/security/sandbox/chromium/base/threading/thread_id_name_manager.cc b/security/sandbox/chromium/base/threading/thread_id_name_manager.cc new file mode 100644 index 000000000..56cfa273a --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_id_name_manager.cc @@ -0,0 +1,112 @@ +// 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/thread_id_name_manager.h" + +#include <stdlib.h> +#include <string.h> + +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "base/strings/string_util.h" + +namespace base { +namespace { + +static const char kDefaultName[] = ""; +static std::string* g_default_name; + +} + +ThreadIdNameManager::ThreadIdNameManager() + : main_process_name_(NULL), + main_process_id_(kInvalidThreadId) { + g_default_name = new std::string(kDefaultName); + + AutoLock locked(lock_); + name_to_interned_name_[kDefaultName] = g_default_name; +} + +ThreadIdNameManager::~ThreadIdNameManager() { +} + +ThreadIdNameManager* ThreadIdNameManager::GetInstance() { + return Singleton<ThreadIdNameManager, + LeakySingletonTraits<ThreadIdNameManager> >::get(); +} + +const char* ThreadIdNameManager::GetDefaultInternedString() { + return g_default_name->c_str(); +} + +void ThreadIdNameManager::RegisterThread(PlatformThreadHandle::Handle handle, + PlatformThreadId id) { + AutoLock locked(lock_); + thread_id_to_handle_[id] = handle; + thread_handle_to_interned_name_[handle] = + name_to_interned_name_[kDefaultName]; +} + +void ThreadIdNameManager::SetName(PlatformThreadId id, + const std::string& name) { + AutoLock locked(lock_); + NameToInternedNameMap::iterator iter = name_to_interned_name_.find(name); + std::string* leaked_str = NULL; + if (iter != name_to_interned_name_.end()) { + leaked_str = iter->second; + } else { + leaked_str = new std::string(name); + name_to_interned_name_[name] = leaked_str; + } + + ThreadIdToHandleMap::iterator id_to_handle_iter = + thread_id_to_handle_.find(id); + + // The main thread of a process will not be created as a Thread object which + // means there is no PlatformThreadHandler registered. + if (id_to_handle_iter == thread_id_to_handle_.end()) { + main_process_name_ = leaked_str; + main_process_id_ = id; + return; + } + thread_handle_to_interned_name_[id_to_handle_iter->second] = leaked_str; +} + +const char* ThreadIdNameManager::GetName(PlatformThreadId id) { + AutoLock locked(lock_); + + if (id == main_process_id_) + return main_process_name_->c_str(); + + ThreadIdToHandleMap::iterator id_to_handle_iter = + thread_id_to_handle_.find(id); + if (id_to_handle_iter == thread_id_to_handle_.end()) + return name_to_interned_name_[kDefaultName]->c_str(); + + ThreadHandleToInternedNameMap::iterator handle_to_name_iter = + thread_handle_to_interned_name_.find(id_to_handle_iter->second); + return handle_to_name_iter->second->c_str(); +} + +void ThreadIdNameManager::RemoveName(PlatformThreadHandle::Handle handle, + PlatformThreadId id) { + AutoLock locked(lock_); + ThreadHandleToInternedNameMap::iterator handle_to_name_iter = + thread_handle_to_interned_name_.find(handle); + + DCHECK(handle_to_name_iter != thread_handle_to_interned_name_.end()); + thread_handle_to_interned_name_.erase(handle_to_name_iter); + + ThreadIdToHandleMap::iterator id_to_handle_iter = + thread_id_to_handle_.find(id); + DCHECK((id_to_handle_iter!= thread_id_to_handle_.end())); + // The given |id| may have been re-used by the system. Make sure the + // mapping points to the provided |handle| before removal. + if (id_to_handle_iter->second != handle) + return; + + thread_id_to_handle_.erase(id_to_handle_iter); +} + +} // namespace base diff --git a/security/sandbox/chromium/base/threading/thread_id_name_manager.h b/security/sandbox/chromium/base/threading/thread_id_name_manager.h new file mode 100644 index 000000000..f469b605e --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_id_name_manager.h @@ -0,0 +1,68 @@ +// 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. + +#ifndef BASE_THREADING_THREAD_ID_NAME_MANAGER_H_ +#define BASE_THREADING_THREAD_ID_NAME_MANAGER_H_ + +#include <map> +#include <string> + +#include "base/base_export.h" +#include "base/macros.h" +#include "base/synchronization/lock.h" +#include "base/threading/platform_thread.h" + +namespace base { + +template <typename T> +struct DefaultSingletonTraits; + +class BASE_EXPORT ThreadIdNameManager { + public: + static ThreadIdNameManager* GetInstance(); + + static const char* GetDefaultInternedString(); + + // Register the mapping between a thread |id| and |handle|. + void RegisterThread(PlatformThreadHandle::Handle handle, PlatformThreadId id); + + // Set the name for the given id. + void SetName(PlatformThreadId id, const std::string& name); + + // Get the name for the given id. + const char* GetName(PlatformThreadId id); + + // Remove the name for the given id. + void RemoveName(PlatformThreadHandle::Handle handle, PlatformThreadId id); + + private: + friend struct DefaultSingletonTraits<ThreadIdNameManager>; + + typedef std::map<PlatformThreadId, PlatformThreadHandle::Handle> + ThreadIdToHandleMap; + typedef std::map<PlatformThreadHandle::Handle, std::string*> + ThreadHandleToInternedNameMap; + typedef std::map<std::string, std::string*> NameToInternedNameMap; + + ThreadIdNameManager(); + ~ThreadIdNameManager(); + + // lock_ protects the name_to_interned_name_, thread_id_to_handle_ and + // thread_handle_to_interned_name_ maps. + Lock lock_; + + NameToInternedNameMap name_to_interned_name_; + ThreadIdToHandleMap thread_id_to_handle_; + ThreadHandleToInternedNameMap thread_handle_to_interned_name_; + + // Treat the main process specially as there is no PlatformThreadHandle. + std::string* main_process_name_; + PlatformThreadId main_process_id_; + + DISALLOW_COPY_AND_ASSIGN(ThreadIdNameManager); +}; + +} // namespace base + +#endif // BASE_THREADING_THREAD_ID_NAME_MANAGER_H_ diff --git a/security/sandbox/chromium/base/threading/thread_local.h b/security/sandbox/chromium/base/threading/thread_local.h new file mode 100644 index 000000000..f40420cd2 --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_local.h @@ -0,0 +1,134 @@ +// Copyright (c) 2011 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. + +// WARNING: Thread local storage is a bit tricky to get right. Please make +// sure that this is really the proper solution for what you're trying to +// achieve. Don't prematurely optimize, most likely you can just use a Lock. +// +// These classes implement a wrapper around the platform's TLS storage +// mechanism. On construction, they will allocate a TLS slot, and free the +// TLS slot on destruction. No memory management (creation or destruction) is +// handled. This means for uses of ThreadLocalPointer, you must correctly +// manage the memory yourself, these classes will not destroy the pointer for +// you. There are no at-thread-exit actions taken by these classes. +// +// ThreadLocalPointer<Type> wraps a Type*. It performs no creation or +// destruction, so memory management must be handled elsewhere. The first call +// to Get() on a thread will return NULL. You can update the pointer with a +// call to Set(). +// +// ThreadLocalBoolean wraps a bool. It will default to false if it has never +// been set otherwise with Set(). +// +// Thread Safety: An instance of ThreadLocalStorage is completely thread safe +// once it has been created. If you want to dynamically create an instance, +// you must of course properly deal with safety and race conditions. This +// means a function-level static initializer is generally inappropiate. +// +// In Android, the system TLS is limited, the implementation is backed with +// ThreadLocalStorage. +// +// Example usage: +// // My class is logically attached to a single thread. We cache a pointer +// // on the thread it was created on, so we can implement current(). +// MyClass::MyClass() { +// DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() == NULL); +// Singleton<ThreadLocalPointer<MyClass> >::get()->Set(this); +// } +// +// MyClass::~MyClass() { +// DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() != NULL); +// Singleton<ThreadLocalPointer<MyClass> >::get()->Set(NULL); +// } +// +// // Return the current MyClass associated with the calling thread, can be +// // NULL if there isn't a MyClass associated. +// MyClass* MyClass::current() { +// return Singleton<ThreadLocalPointer<MyClass> >::get()->Get(); +// } + +#ifndef BASE_THREADING_THREAD_LOCAL_H_ +#define BASE_THREADING_THREAD_LOCAL_H_ + +#include "base/base_export.h" +#include "base/macros.h" +#include "base/threading/thread_local_storage.h" +#include "build/build_config.h" + +#if defined(OS_POSIX) +#include <pthread.h> +#endif + +namespace base { +namespace internal { + +// Helper functions that abstract the cross-platform APIs. Do not use directly. +struct BASE_EXPORT ThreadLocalPlatform { +#if defined(OS_WIN) + typedef unsigned long SlotType; +#elif defined(OS_ANDROID) + typedef ThreadLocalStorage::StaticSlot SlotType; +#elif defined(OS_POSIX) + typedef pthread_key_t SlotType; +#endif + + static void AllocateSlot(SlotType* slot); + static void FreeSlot(SlotType slot); + static void* GetValueFromSlot(SlotType slot); + static void SetValueInSlot(SlotType slot, void* value); +}; + +} // namespace internal + +template <typename Type> +class ThreadLocalPointer { + public: + ThreadLocalPointer() : slot_() { + internal::ThreadLocalPlatform::AllocateSlot(&slot_); + } + + ~ThreadLocalPointer() { + internal::ThreadLocalPlatform::FreeSlot(slot_); + } + + Type* Get() { + return static_cast<Type*>( + internal::ThreadLocalPlatform::GetValueFromSlot(slot_)); + } + + void Set(Type* ptr) { + internal::ThreadLocalPlatform::SetValueInSlot( + slot_, const_cast<void*>(static_cast<const void*>(ptr))); + } + + private: + typedef internal::ThreadLocalPlatform::SlotType SlotType; + + SlotType slot_; + + DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer<Type>); +}; + +class ThreadLocalBoolean { + public: + ThreadLocalBoolean() {} + ~ThreadLocalBoolean() {} + + bool Get() { + return tlp_.Get() != NULL; + } + + void Set(bool val) { + tlp_.Set(val ? this : NULL); + } + + private: + ThreadLocalPointer<void> tlp_; + + DISALLOW_COPY_AND_ASSIGN(ThreadLocalBoolean); +}; + +} // namespace base + +#endif // BASE_THREADING_THREAD_LOCAL_H_ diff --git a/security/sandbox/chromium/base/threading/thread_local_posix.cc b/security/sandbox/chromium/base/threading/thread_local_posix.cc new file mode 100644 index 000000000..8bc46ad19 --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_local_posix.cc @@ -0,0 +1,43 @@ +// Copyright (c) 2011 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/thread_local.h" + +#include <pthread.h> + +#include "base/logging.h" +#include "build/build_config.h" + +#if !defined(OS_ANDROID) + +namespace base { +namespace internal { + +// static +void ThreadLocalPlatform::AllocateSlot(SlotType* slot) { + int error = pthread_key_create(slot, NULL); + CHECK_EQ(error, 0); +} + +// static +void ThreadLocalPlatform::FreeSlot(SlotType slot) { + int error = pthread_key_delete(slot); + DCHECK_EQ(0, error); +} + +// static +void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) { + return pthread_getspecific(slot); +} + +// static +void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) { + int error = pthread_setspecific(slot, value); + DCHECK_EQ(error, 0); +} + +} // namespace internal +} // namespace base + +#endif // !defined(OS_ANDROID) diff --git a/security/sandbox/chromium/base/threading/thread_local_storage.h b/security/sandbox/chromium/base/threading/thread_local_storage.h new file mode 100644 index 000000000..013b0aeff --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_local_storage.h @@ -0,0 +1,148 @@ +// 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. + +#ifndef BASE_THREADING_THREAD_LOCAL_STORAGE_H_ +#define BASE_THREADING_THREAD_LOCAL_STORAGE_H_ + +#include "base/atomicops.h" +#include "base/base_export.h" +#include "base/macros.h" +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <windows.h> +#elif defined(OS_POSIX) +#include <pthread.h> +#endif + +namespace base { + +namespace internal { + +// WARNING: You should *NOT* be using this class directly. +// PlatformThreadLocalStorage is low-level abstraction to the OS's TLS +// interface, you should instead be using ThreadLocalStorage::StaticSlot/Slot. +class BASE_EXPORT PlatformThreadLocalStorage { + public: + +#if defined(OS_WIN) + typedef unsigned long TLSKey; + enum : unsigned { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES }; +#elif defined(OS_POSIX) + typedef pthread_key_t TLSKey; + // The following is a "reserved key" which is used in our generic Chromium + // ThreadLocalStorage implementation. We expect that an OS will not return + // such a key, but if it is returned (i.e., the OS tries to allocate it) we + // will just request another key. + enum { TLS_KEY_OUT_OF_INDEXES = 0x7FFFFFFF }; +#endif + + // The following methods need to be supported on each OS platform, so that + // the Chromium ThreadLocalStore functionality can be constructed. + // Chromium will use these methods to acquire a single OS slot, and then use + // that to support a much larger number of Chromium slots (independent of the + // OS restrictions). + // The following returns true if it successfully is able to return an OS + // key in |key|. + static bool AllocTLS(TLSKey* key); + // Note: FreeTLS() doesn't have to be called, it is fine with this leak, OS + // might not reuse released slot, you might just reset the TLS value with + // SetTLSValue(). + static void FreeTLS(TLSKey key); + static void SetTLSValue(TLSKey key, void* value); + static void* GetTLSValue(TLSKey key); + + // Each platform (OS implementation) is required to call this method on each + // terminating thread when the thread is about to terminate. This method + // will then call all registered destructors for slots in Chromium + // ThreadLocalStorage, until there are no slot values remaining as having + // been set on this thread. + // Destructors may end up being called multiple times on a terminating + // thread, as other destructors may re-set slots that were previously + // destroyed. +#if defined(OS_WIN) + // Since Windows which doesn't support TLS destructor, the implementation + // should use GetTLSValue() to retrieve the value of TLS slot. + static void OnThreadExit(); +#elif defined(OS_POSIX) + // |Value| is the data stored in TLS slot, The implementation can't use + // GetTLSValue() to retrieve the value of slot as it has already been reset + // in Posix. + static void OnThreadExit(void* value); +#endif +}; + +} // namespace internal + +// Wrapper for thread local storage. This class doesn't do much except provide +// an API for portability. +class BASE_EXPORT ThreadLocalStorage { + public: + + // Prototype for the TLS destructor function, which can be optionally used to + // cleanup thread local storage on thread exit. 'value' is the data that is + // stored in thread local storage. + typedef void (*TLSDestructorFunc)(void* value); + + // StaticSlot uses its own struct initializer-list style static + // initialization, as base's LINKER_INITIALIZED requires a constructor and on + // some compilers (notably gcc 4.4) this still ends up needing runtime + // initialization. + #define TLS_INITIALIZER {0} + + // A key representing one value stored in TLS. + // Initialize like + // ThreadLocalStorage::StaticSlot my_slot = TLS_INITIALIZER; + // If you're not using a static variable, use the convenience class + // ThreadLocalStorage::Slot (below) instead. + struct BASE_EXPORT StaticSlot { + // Set up the TLS slot. Called by the constructor. + // 'destructor' is a pointer to a function to perform per-thread cleanup of + // this object. If set to NULL, no cleanup is done for this TLS slot. + void Initialize(TLSDestructorFunc destructor); + + // Free a previously allocated TLS 'slot'. + // If a destructor was set for this slot, removes + // the destructor so that remaining threads exiting + // will not free data. + void Free(); + + // Get the thread-local value stored in slot 'slot'. + // Values are guaranteed to initially be zero. + void* Get() const; + + // Set the thread-local value stored in slot 'slot' to + // value 'value'. + void Set(void* value); + + bool initialized() const { + return base::subtle::Acquire_Load(&initialized_) != 0; + } + + // The internals of this struct should be considered private. + base::subtle::Atomic32 initialized_; + int slot_; + }; + + // A convenience wrapper around StaticSlot with a constructor. Can be used + // as a member variable. + class BASE_EXPORT Slot : public StaticSlot { + public: + // Calls StaticSlot::Initialize(). + explicit Slot(TLSDestructorFunc destructor = NULL); + + private: + using StaticSlot::initialized_; + using StaticSlot::slot_; + + DISALLOW_COPY_AND_ASSIGN(Slot); + }; + + private: + DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage); +}; + +} // namespace base + +#endif // BASE_THREADING_THREAD_LOCAL_STORAGE_H_ diff --git a/security/sandbox/chromium/base/threading/thread_local_win.cc b/security/sandbox/chromium/base/threading/thread_local_win.cc new file mode 100644 index 000000000..1c74e4213 --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_local_win.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2010 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/thread_local.h" + +#include <windows.h> + +#include "base/logging.h" + +namespace base { +namespace internal { + +// static +void ThreadLocalPlatform::AllocateSlot(SlotType* slot) { + *slot = TlsAlloc(); + CHECK_NE(*slot, TLS_OUT_OF_INDEXES); +} + +// static +void ThreadLocalPlatform::FreeSlot(SlotType slot) { + if (!TlsFree(slot)) { + NOTREACHED() << "Failed to deallocate tls slot with TlsFree()."; + } +} + +// static +void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) { + return TlsGetValue(slot); +} + +// static +void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) { + if (!TlsSetValue(slot, value)) { + LOG(FATAL) << "Failed to TlsSetValue()."; + } +} + +} // namespace internal +} // namespace base diff --git a/security/sandbox/chromium/base/threading/thread_restrictions.cc b/security/sandbox/chromium/base/threading/thread_restrictions.cc new file mode 100644 index 000000000..00306c5ae --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_restrictions.cc @@ -0,0 +1,85 @@ +// 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/thread_restrictions.h" + +#if ENABLE_THREAD_RESTRICTIONS + +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/threading/thread_local.h" + +namespace base { + +namespace { + +LazyInstance<ThreadLocalBoolean>::Leaky + g_io_disallowed = LAZY_INSTANCE_INITIALIZER; + +LazyInstance<ThreadLocalBoolean>::Leaky + g_singleton_disallowed = LAZY_INSTANCE_INITIALIZER; + +LazyInstance<ThreadLocalBoolean>::Leaky + g_wait_disallowed = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +// static +bool ThreadRestrictions::SetIOAllowed(bool allowed) { + bool previous_disallowed = g_io_disallowed.Get().Get(); + g_io_disallowed.Get().Set(!allowed); + return !previous_disallowed; +} + +// static +void ThreadRestrictions::AssertIOAllowed() { + if (g_io_disallowed.Get().Get()) { + LOG(FATAL) << + "Function marked as IO-only was called from a thread that " + "disallows IO! If this thread really should be allowed to " + "make IO calls, adjust the call to " + "base::ThreadRestrictions::SetIOAllowed() in this thread's " + "startup."; + } +} + +// static +bool ThreadRestrictions::SetSingletonAllowed(bool allowed) { + bool previous_disallowed = g_singleton_disallowed.Get().Get(); + g_singleton_disallowed.Get().Set(!allowed); + return !previous_disallowed; +} + +// static +void ThreadRestrictions::AssertSingletonAllowed() { + if (g_singleton_disallowed.Get().Get()) { + LOG(FATAL) << "LazyInstance/Singleton is not allowed to be used on this " + << "thread. Most likely it's because this thread is not " + << "joinable, so AtExitManager may have deleted the object " + << "on shutdown, leading to a potential shutdown crash."; + } +} + +// static +void ThreadRestrictions::DisallowWaiting() { + g_wait_disallowed.Get().Set(true); +} + +// static +void ThreadRestrictions::AssertWaitAllowed() { + if (g_wait_disallowed.Get().Get()) { + LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent " + << "jank and deadlock."; + } +} + +bool ThreadRestrictions::SetWaitAllowed(bool allowed) { + bool previous_disallowed = g_wait_disallowed.Get().Get(); + g_wait_disallowed.Get().Set(!allowed); + return !previous_disallowed; +} + +} // namespace base + +#endif // ENABLE_THREAD_RESTRICTIONS diff --git a/security/sandbox/chromium/base/threading/thread_restrictions.h b/security/sandbox/chromium/base/threading/thread_restrictions.h new file mode 100644 index 000000000..eec00fbb7 --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_restrictions.h @@ -0,0 +1,266 @@ +// 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. + +#ifndef BASE_THREADING_THREAD_RESTRICTIONS_H_ +#define BASE_THREADING_THREAD_RESTRICTIONS_H_ + +#include "base/base_export.h" +#include "base/macros.h" + +// See comment at top of thread_checker.h +#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) +#define ENABLE_THREAD_RESTRICTIONS 1 +#else +#define ENABLE_THREAD_RESTRICTIONS 0 +#endif + +class BrowserProcessImpl; +class HistogramSynchronizer; +class NativeBackendKWallet; +class ScopedAllowWaitForLegacyWebViewApi; + +namespace cc { +class CompletionEvent; +class SingleThreadTaskGraphRunner; +} +namespace chromeos { +class BlockingMethodCaller; +namespace system { +class StatisticsProviderImpl; +} +} +namespace chrome_browser_net { +class Predictor; +} +namespace content { +class BrowserGpuChannelHostFactory; +class BrowserGpuMemoryBufferManager; +class BrowserShutdownProfileDumper; +class BrowserTestBase; +class GpuChannelHost; +class NestedMessagePumpAndroid; +class ScopedAllowWaitForAndroidLayoutTests; +class ScopedAllowWaitForDebugURL; +class SoftwareOutputDeviceMus; +class TextInputClientMac; +class RasterWorkerPool; +} // namespace content +namespace dbus { +class Bus; +} +namespace disk_cache { +class BackendImpl; +class InFlightIO; +} +namespace gles2 { +class CommandBufferClientImpl; +} +namespace mojo { +namespace common { +class MessagePumpMojo; +} +} +namespace mus { +class CommandBufferLocal; +class GpuState; +} +namespace net { +class NetworkChangeNotifierMac; +namespace internal { +class AddressTrackerLinux; +} +} + +namespace remoting { +class AutoThread; +} + +namespace ui { +class WindowResizeHelperMac; +} + +namespace views { +class WindowManagerConnection; +} + +namespace base { + +namespace android { +class JavaHandlerThread; +} + +class SequencedWorkerPool; +class SimpleThread; +class Thread; +class ThreadTestHelper; + +// Certain behavior is disallowed on certain threads. ThreadRestrictions helps +// enforce these rules. Examples of such rules: +// +// * Do not do blocking IO (makes the thread janky) +// * Do not access Singleton/LazyInstance (may lead to shutdown crashes) +// +// Here's more about how the protection works: +// +// 1) If a thread should not be allowed to make IO calls, mark it: +// base::ThreadRestrictions::SetIOAllowed(false); +// By default, threads *are* allowed to make IO calls. +// In Chrome browser code, IO calls should be proxied to the File thread. +// +// 2) If a function makes a call that will go out to disk, check whether the +// current thread is allowed: +// base::ThreadRestrictions::AssertIOAllowed(); +// +// +// Style tip: where should you put AssertIOAllowed checks? It's best +// if you put them as close to the disk access as possible, at the +// lowest level. This rule is simple to follow and helps catch all +// callers. For example, if your function GoDoSomeBlockingDiskCall() +// only calls other functions in Chrome and not fopen(), you should go +// add the AssertIOAllowed checks in the helper functions. + +class BASE_EXPORT ThreadRestrictions { + public: + // Constructing a ScopedAllowIO temporarily allows IO for the current + // thread. Doing this is almost certainly always incorrect. + class BASE_EXPORT ScopedAllowIO { + public: + ScopedAllowIO() { previous_value_ = SetIOAllowed(true); } + ~ScopedAllowIO() { SetIOAllowed(previous_value_); } + private: + // Whether IO is allowed when the ScopedAllowIO was constructed. + bool previous_value_; + + DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO); + }; + + // Constructing a ScopedAllowSingleton temporarily allows accessing for the + // current thread. Doing this is almost always incorrect. + class BASE_EXPORT ScopedAllowSingleton { + public: + ScopedAllowSingleton() { previous_value_ = SetSingletonAllowed(true); } + ~ScopedAllowSingleton() { SetSingletonAllowed(previous_value_); } + private: + // Whether singleton use is allowed when the ScopedAllowSingleton was + // constructed. + bool previous_value_; + + DISALLOW_COPY_AND_ASSIGN(ScopedAllowSingleton); + }; + +#if ENABLE_THREAD_RESTRICTIONS + // Set whether the current thread to make IO calls. + // Threads start out in the *allowed* state. + // Returns the previous value. + static bool SetIOAllowed(bool allowed); + + // Check whether the current thread is allowed to make IO calls, + // and DCHECK if not. See the block comment above the class for + // a discussion of where to add these checks. + static void AssertIOAllowed(); + + // Set whether the current thread can use singletons. Returns the previous + // value. + static bool SetSingletonAllowed(bool allowed); + + // Check whether the current thread is allowed to use singletons (Singleton / + // LazyInstance). DCHECKs if not. + static void AssertSingletonAllowed(); + + // Disable waiting on the current thread. Threads start out in the *allowed* + // state. Returns the previous value. + static void DisallowWaiting(); + + // Check whether the current thread is allowed to wait, and DCHECK if not. + static void AssertWaitAllowed(); +#else + // Inline the empty definitions of these functions so that they can be + // compiled out. + static bool SetIOAllowed(bool allowed) { return true; } + static void AssertIOAllowed() {} + static bool SetSingletonAllowed(bool allowed) { return true; } + static void AssertSingletonAllowed() {} + static void DisallowWaiting() {} + static void AssertWaitAllowed() {} +#endif + + private: + // DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to jam or brettw first. + // BEGIN ALLOWED USAGE. + friend class content::BrowserShutdownProfileDumper; + friend class content::BrowserTestBase; + friend class content::NestedMessagePumpAndroid; + friend class content::ScopedAllowWaitForAndroidLayoutTests; + friend class content::ScopedAllowWaitForDebugURL; + friend class ::HistogramSynchronizer; + friend class ::ScopedAllowWaitForLegacyWebViewApi; + friend class cc::CompletionEvent; + friend class cc::SingleThreadTaskGraphRunner; + friend class content::RasterWorkerPool; + friend class remoting::AutoThread; + friend class ui::WindowResizeHelperMac; + friend class MessagePumpDefault; + friend class SequencedWorkerPool; + friend class SimpleThread; + friend class Thread; + friend class ThreadTestHelper; + friend class PlatformThread; + friend class android::JavaHandlerThread; + friend class gles2::CommandBufferClientImpl; + friend class mojo::common::MessagePumpMojo; + friend class mus::CommandBufferLocal; + friend class mus::GpuState; + + // END ALLOWED USAGE. + // BEGIN USAGE THAT NEEDS TO BE FIXED. + friend class ::chromeos::BlockingMethodCaller; // http://crbug.com/125360 + friend class ::chromeos::system::StatisticsProviderImpl; // http://crbug.com/125385 + friend class chrome_browser_net::Predictor; // http://crbug.com/78451 + friend class + content::BrowserGpuChannelHostFactory; // http://crbug.com/125248 + friend class + content::BrowserGpuMemoryBufferManager; // http://crbug.com/420368 + friend class content::GpuChannelHost; // http://crbug.com/125264 + friend class content::TextInputClientMac; // http://crbug.com/121917 + friend class dbus::Bus; // http://crbug.com/125222 + friend class disk_cache::BackendImpl; // http://crbug.com/74623 + friend class disk_cache::InFlightIO; // http://crbug.com/74623 + friend class net::internal::AddressTrackerLinux; // http://crbug.com/125097 + friend class net::NetworkChangeNotifierMac; // http://crbug.com/125097 + friend class ::BrowserProcessImpl; // http://crbug.com/125207 + friend class ::NativeBackendKWallet; // http://crbug.com/125331 +#if !defined(OFFICIAL_BUILD) + friend class content::SoftwareOutputDeviceMus; // Interim non-production code +#endif + friend class views::WindowManagerConnection; +// END USAGE THAT NEEDS TO BE FIXED. + +#if ENABLE_THREAD_RESTRICTIONS + static bool SetWaitAllowed(bool allowed); +#else + static bool SetWaitAllowed(bool allowed) { return true; } +#endif + + // Constructing a ScopedAllowWait temporarily allows waiting on the current + // thread. Doing this is almost always incorrect, which is why we limit who + // can use this through friend. If you find yourself needing to use this, find + // another way. Talk to jam or brettw. + class BASE_EXPORT ScopedAllowWait { + public: + ScopedAllowWait() { previous_value_ = SetWaitAllowed(true); } + ~ScopedAllowWait() { SetWaitAllowed(previous_value_); } + private: + // Whether singleton use is allowed when the ScopedAllowWait was + // constructed. + bool previous_value_; + + DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait); + }; + + DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions); +}; + +} // namespace base + +#endif // BASE_THREADING_THREAD_RESTRICTIONS_H_ |