summaryrefslogtreecommitdiff
path: root/base/threading
diff options
context:
space:
mode:
Diffstat (limited to 'base/threading')
-rw-r--r--base/threading/platform_thread.h115
-rw-r--r--base/threading/platform_thread_posix.cc262
-rw-r--r--base/threading/thread.cc177
-rw-r--r--base/threading/thread.h191
-rw-r--r--base/threading/thread_collision_warner.cc64
-rw-r--r--base/threading/thread_collision_warner.h244
6 files changed, 1053 insertions, 0 deletions
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
new file mode 100644
index 0000000..8382bbe
--- /dev/null
+++ b/base/threading/platform_thread.h
@@ -0,0 +1,115 @@
+// 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: 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_
+#pragma once
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#if defined(OS_MACOSX)
+#include <mach/mach.h>
+#else // OS_POSIX && !OS_MACOSX
+#include <unistd.h>
+#endif
+#endif
+
+namespace base {
+
+// PlatformThreadHandle should not be assumed to be a numeric type, since the
+// standard intends to allow pthread_t to be a structure. This means you
+// should not initialize it to a value, like 0. If it's a member variable, the
+// constructor can safely "value initialize" using () in the initializer list.
+#if defined(OS_WIN)
+typedef DWORD PlatformThreadId;
+typedef void* PlatformThreadHandle; // HANDLE
+const PlatformThreadHandle kNullThreadHandle = NULL;
+#elif defined(OS_POSIX)
+typedef pthread_t PlatformThreadHandle;
+const PlatformThreadHandle kNullThreadHandle = 0;
+#if defined(OS_MACOSX)
+typedef mach_port_t PlatformThreadId;
+#else // OS_POSIX && !OS_MACOSX
+typedef pid_t PlatformThreadId;
+#endif
+#endif
+
+const PlatformThreadId kInvalidThreadId = 0;
+
+// Valid values for SetThreadPriority()
+enum ThreadPriority{
+ kThreadPriority_Normal,
+ // Suitable for low-latency, glitch-resistant audio.
+ kThreadPriority_RealtimeAudio
+};
+
+// 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 ~Delegate() {}
+ virtual void ThreadMain() = 0;
+ };
+
+ // Gets the current thread id, which may be useful for logging purposes.
+ static PlatformThreadId CurrentId();
+
+ // Yield the current thread so another thread can be scheduled.
+ static void YieldCurrentThread();
+
+ // Sleeps for the specified duration (units are milliseconds).
+ static void Sleep(int duration_ms);
+
+ // Sets the thread name visible to debuggers/tools. This has no effect
+ // otherwise. This name pointer is not copied internally. Thus, it must stay
+ // valid until the thread ends.
+ static void SetName(const char* 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);
+
+ // 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);
+
+ static void SetThreadPriority(PlatformThreadHandle handle,
+ ThreadPriority priority);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_PLATFORM_THREAD_H_
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
new file mode 100644
index 0000000..c924a16
--- /dev/null
+++ b/base/threading/platform_thread_posix.cc
@@ -0,0 +1,262 @@
+// 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/platform_thread.h"
+
+#include <errno.h>
+#include <sched.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/safe_strerror_posix.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_MACOSX)
+#include <mach/mach.h>
+#include <sys/resource.h>
+#include <algorithm>
+#endif
+
+#if defined(OS_LINUX)
+#include <dlfcn.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#endif
+
+#if defined(OS_NACL)
+#include <sys/nacl_syscalls.h>
+#endif
+
+namespace base {
+
+#if defined(OS_MACOSX)
+void InitThreading();
+#endif
+
+namespace {
+
+static ThreadLocalPointer<char> current_thread_name;
+
+struct ThreadParams {
+ PlatformThread::Delegate* delegate;
+ bool joinable;
+};
+
+void* ThreadFunc(void* params) {
+ ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+ PlatformThread::Delegate* delegate = thread_params->delegate;
+ if (!thread_params->joinable)
+ base::ThreadRestrictions::SetSingletonAllowed(false);
+ delete thread_params;
+ delegate->ThreadMain();
+#if defined(OS_ANDROID)
+ base::android::DetachFromVM();
+#endif
+ return NULL;
+}
+
+bool CreateThread(size_t stack_size, bool joinable,
+ PlatformThread::Delegate* delegate,
+ PlatformThreadHandle* thread_handle) {
+#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.
+ if (!joinable) {
+ pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
+ }
+
+#if defined(OS_MACOSX)
+ // 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
+
+ if (stack_size > 0)
+ pthread_attr_setstacksize(&attributes, stack_size);
+
+ ThreadParams* params = new ThreadParams;
+ params->delegate = delegate;
+ params->joinable = joinable;
+ success = !pthread_create(thread_handle, &attributes, ThreadFunc, params);
+
+ pthread_attr_destroy(&attributes);
+ if (!success)
+ delete params;
+ 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 mach_thread_self();
+#elif defined(OS_LINUX)
+ return syscall(__NR_gettid);
+#elif defined(OS_ANDROID)
+ return gettid();
+#elif defined(OS_FREEBSD)
+ // TODO(BSD): find a better thread ID
+ return reinterpret_cast<int64>(pthread_self());
+#elif defined(OS_NACL) || defined(OS_SOLARIS)
+ return pthread_self();
+#endif
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+ sched_yield();
+}
+
+// static
+void PlatformThread::Sleep(int duration_ms) {
+ struct timespec sleep_time, remaining;
+
+ // Contains the portion of duration_ms >= 1 sec.
+ sleep_time.tv_sec = duration_ms / 1000;
+ duration_ms -= sleep_time.tv_sec * 1000;
+
+ // Contains the portion of duration_ms < 1 sec.
+ sleep_time.tv_nsec = duration_ms * 1000 * 1000; // nanoseconds.
+
+ while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
+ sleep_time = remaining;
+}
+
+// Linux SetName is currently disabled, as we need to distinguish between
+// helper threads (where it's ok to make this call) and the main thread
+// (where making this call renames our process, causing tools like killall
+// to stop working).
+#if 0 && defined(OS_LINUX)
+// static
+void PlatformThread::SetName(const char* name) {
+ // have to cast away const because ThreadLocalPointer does not support const
+ // void*
+ current_thread_name.Set(const_cast<char*>(name));
+
+ // http://0pointer.de/blog/projects/name-your-threads.html
+
+ // glibc recently added support for pthread_setname_np, but it's not
+ // commonly available yet. So test for it at runtime.
+ int (*dynamic_pthread_setname_np)(pthread_t, const char*);
+ *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
+ dlsym(RTLD_DEFAULT, "pthread_setname_np");
+
+ if (dynamic_pthread_setname_np) {
+ // This limit comes from glibc, which gets it from the kernel
+ // (TASK_COMM_LEN).
+ const int kMaxNameLength = 15;
+ std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
+ int err = dynamic_pthread_setname_np(pthread_self(),
+ shortened_name.c_str());
+ if (err < 0)
+ LOG(ERROR) << "pthread_setname_np: " << safe_strerror(err);
+ } else {
+ // Implementing this function without glibc is simple enough. (We
+ // don't do the name length clipping as above because it will be
+ // truncated by the callee (see TASK_COMM_LEN above).)
+ int err = prctl(PR_SET_NAME, name);
+ if (err < 0)
+ PLOG(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) {
+ // have to cast away const because ThreadLocalPointer does not support const
+ // void*
+ current_thread_name.Set(const_cast<char*>(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)
+
+
+#if !defined(OS_MACOSX)
+// Mac is implemented in platform_thread_mac.mm.
+// static
+const char* PlatformThread::GetName() {
+ return current_thread_name.Get();
+}
+#endif
+
+// static
+bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
+ PlatformThreadHandle* thread_handle) {
+ return CreateThread(stack_size, true /* joinable thread */,
+ delegate, thread_handle);
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+ PlatformThreadHandle unused;
+
+ bool result = CreateThread(stack_size, false /* non-joinable thread */,
+ delegate, &unused);
+ 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();
+ pthread_join(thread_handle, NULL);
+}
+
+#if !defined(OS_MACOSX)
+// Mac OS X uses lower-level mach APIs
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle, ThreadPriority) {
+ // TODO(crogers): implement
+ NOTIMPLEMENTED();
+}
+#endif
+
+} // namespace base
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
new file mode 100644
index 0000000..616aac8
--- /dev/null
+++ b/base/threading/thread.cc
@@ -0,0 +1,177 @@
+// 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.h"
+
+#include "base/lazy_instance.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread_local.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+namespace {
+
+// We use this thread-local variable to record whether or not a thread exited
+// because its Stop method was called. This allows us to catch cases where
+// MessageLoop::Quit() is called directly, which is unexpected when using a
+// Thread to setup and run a MessageLoop.
+base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool(
+ base::LINKER_INITIALIZED);
+
+} // namespace
+
+// This task is used to trigger the message loop to exit.
+class ThreadQuitTask : public Task {
+ public:
+ virtual void Run() {
+ MessageLoop::current()->Quit();
+ Thread::SetThreadWasQuitProperly(true);
+ }
+};
+
+// Used to pass data to ThreadMain. This structure is allocated on the stack
+// from within StartWithOptions.
+struct Thread::StartupData {
+ // We get away with a const reference here because of how we are allocated.
+ const Thread::Options& options;
+
+ // Used to synchronize thread startup.
+ WaitableEvent event;
+
+ explicit StartupData(const Options& opt)
+ : options(opt),
+ event(false, false) {}
+};
+
+Thread::Thread(const char* name)
+ : started_(false),
+ stopping_(false),
+ startup_data_(NULL),
+ thread_(0),
+ message_loop_(NULL),
+ thread_id_(kInvalidThreadId),
+ name_(name) {
+}
+
+Thread::~Thread() {
+ Stop();
+}
+
+bool Thread::Start() {
+ return StartWithOptions(Options());
+}
+
+bool Thread::StartWithOptions(const Options& options) {
+ DCHECK(!message_loop_);
+
+ SetThreadWasQuitProperly(false);
+
+ StartupData startup_data(options);
+ startup_data_ = &startup_data;
+
+ if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
+ DLOG(ERROR) << "failed to create thread";
+ startup_data_ = NULL;
+ return false;
+ }
+
+ // Wait for the thread to start and initialize message_loop_
+ startup_data.event.Wait();
+
+ // set it to NULL so we don't keep a pointer to some object on the stack.
+ startup_data_ = NULL;
+ started_ = true;
+
+ DCHECK(message_loop_);
+ return true;
+}
+
+void Thread::Stop() {
+ if (!thread_was_started())
+ return;
+
+ StopSoon();
+
+ // Wait for the thread to exit.
+ //
+ // TODO(darin): Unfortunately, we need to keep message_loop_ around until
+ // the thread exits. Some consumers are abusing the API. Make them stop.
+ //
+ PlatformThread::Join(thread_);
+
+ // The thread should NULL message_loop_ on exit.
+ DCHECK(!message_loop_);
+
+ // The thread no longer needs to be joined.
+ started_ = false;
+
+ stopping_ = false;
+}
+
+void Thread::StopSoon() {
+ // We should only be called on the same thread that started us.
+
+ // Reading thread_id_ without a lock can lead to a benign data race
+ // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer.
+ DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId());
+
+ if (stopping_ || !message_loop_)
+ return;
+
+ stopping_ = true;
+ message_loop_->PostTask(FROM_HERE, new ThreadQuitTask());
+}
+
+void Thread::Run(MessageLoop* message_loop) {
+ message_loop->Run();
+}
+
+void Thread::SetThreadWasQuitProperly(bool flag) {
+ lazy_tls_bool.Pointer()->Set(flag);
+}
+
+bool Thread::GetThreadWasQuitProperly() {
+ bool quit_properly = true;
+#ifndef NDEBUG
+ quit_properly = lazy_tls_bool.Pointer()->Get();
+#endif
+ return quit_properly;
+}
+
+void Thread::ThreadMain() {
+ {
+ // The message loop for this thread.
+ MessageLoop message_loop(startup_data_->options.message_loop_type);
+
+ // Complete the initialization of our Thread object.
+ thread_id_ = PlatformThread::CurrentId();
+ PlatformThread::SetName(name_.c_str());
+ ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector.
+ message_loop.set_thread_name(name_);
+ message_loop_ = &message_loop;
+
+ // Let the thread do extra initialization.
+ // Let's do this before signaling we are started.
+ Init();
+
+ startup_data_->event.Signal();
+ // startup_data_ can't be touched anymore since the starting thread is now
+ // unlocked.
+
+ Run(message_loop_);
+
+ // Let the thread do extra cleanup.
+ CleanUp();
+
+ // Assert that MessageLoop::Quit was called by ThreadQuitTask.
+ DCHECK(GetThreadWasQuitProperly());
+
+ // We can't receive messages anymore.
+ message_loop_ = NULL;
+ }
+ thread_id_ = kInvalidThreadId;
+}
+
+} // namespace base
diff --git a/base/threading/thread.h b/base/threading/thread.h
new file mode 100644
index 0000000..d7451ec
--- /dev/null
+++ b/base/threading/thread.h
@@ -0,0 +1,191 @@
+// 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_THREAD_H_
+#define BASE_THREAD_H_
+#pragma once
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// A simple thread abstraction that establishes a MessageLoop on a new thread.
+// The consumer uses the MessageLoop of the thread to cause code to execute on
+// the thread. When this object is destroyed the thread is terminated. All
+// pending tasks queued on the thread's message loop will run to completion
+// before the thread is terminated.
+//
+// After the thread is stopped, the destruction sequence is:
+//
+// (1) Thread::CleanUp()
+// (2) MessageLoop::~MessageLoop
+// (3.b) MessageLoop::DestructionObserver::WillDestroyCurrentMessageLoop
+class BASE_EXPORT Thread : PlatformThread::Delegate {
+ public:
+ struct Options {
+ Options() : message_loop_type(MessageLoop::TYPE_DEFAULT), stack_size(0) {}
+ Options(MessageLoop::Type type, size_t size)
+ : message_loop_type(type), stack_size(size) {}
+
+ // Specifies the type of message loop that will be allocated on the thread.
+ MessageLoop::Type message_loop_type;
+
+ // Specifies the maximum stack size that the thread is allowed to use.
+ // This does not necessarily correspond to the thread's initial stack size.
+ // A value of 0 indicates that the default maximum should be used.
+ size_t stack_size;
+ };
+
+ // Constructor.
+ // name is a display string to identify the thread.
+ explicit Thread(const char* name);
+
+ // Destroys the thread, stopping it if necessary.
+ //
+ // NOTE: If you are subclassing from Thread, and you wish for your CleanUp
+ // method to be called, then you need to call Stop() from your destructor.
+ //
+ virtual ~Thread();
+
+ // Starts the thread. Returns true if the thread was successfully started;
+ // otherwise, returns false. Upon successful return, the message_loop()
+ // getter will return non-null.
+ //
+ // Note: This function can't be called on Windows with the loader lock held;
+ // i.e. during a DllMain, global object construction or destruction, atexit()
+ // callback.
+ bool Start();
+
+ // Starts the thread. Behaves exactly like Start in addition to allow to
+ // override the default options.
+ //
+ // Note: This function can't be called on Windows with the loader lock held;
+ // i.e. during a DllMain, global object construction or destruction, atexit()
+ // callback.
+ bool StartWithOptions(const Options& options);
+
+ // Signals the thread to exit and returns once the thread has exited. After
+ // this method returns, the Thread object is completely reset and may be used
+ // as if it were newly constructed (i.e., Start may be called again).
+ //
+ // Stop may be called multiple times and is simply ignored if the thread is
+ // already stopped.
+ //
+ // NOTE: This method is optional. It is not strictly necessary to call this
+ // method as the Thread's destructor will take care of stopping the thread if
+ // necessary.
+ //
+ void Stop();
+
+ // Signals the thread to exit in the near future.
+ //
+ // WARNING: This function is not meant to be commonly used. Use at your own
+ // risk. Calling this function will cause message_loop() to become invalid in
+ // the near future. This function was created to workaround a specific
+ // deadlock on Windows with printer worker thread. In any other case, Stop()
+ // should be used.
+ //
+ // StopSoon should not be called multiple times as it is risky to do so. It
+ // could cause a timing issue in message_loop() access. Call Stop() to reset
+ // the thread object once it is known that the thread has quit.
+ void StopSoon();
+
+ // Returns the message loop for this thread. Use the MessageLoop's
+ // PostTask methods to execute code on the thread. This only returns
+ // non-null after a successful call to Start. After Stop has been called,
+ // this will return NULL.
+ //
+ // NOTE: You must not call this MessageLoop's Quit method directly. Use
+ // the Thread's Stop method instead.
+ //
+ MessageLoop* message_loop() const { return message_loop_; }
+
+ // Returns a MessageLoopProxy for this thread. Use the MessageLoopProxy's
+ // PostTask methods to execute code on the thread. This only returns
+ // non-NULL after a successful call to Start. After Stop has been called,
+ // this will return NULL. Callers can hold on to this even after the thread
+ // is gone.
+ // TODO(sanjeevr): Look into merging MessageLoop and MessageLoopProxy.
+ scoped_refptr<MessageLoopProxy> message_loop_proxy() const {
+ return message_loop_->message_loop_proxy();
+ }
+
+ // Set the name of this thread (for display in debugger too).
+ const std::string &thread_name() { return name_; }
+
+ // The native thread handle.
+ PlatformThreadHandle thread_handle() { return thread_; }
+
+ // The thread ID.
+ PlatformThreadId thread_id() const { return thread_id_; }
+
+ // Returns true if the thread has been started, and not yet stopped.
+ // When a thread is running, |thread_id_| is a valid id.
+ bool IsRunning() const { return thread_id_ != kInvalidThreadId; }
+
+ protected:
+ // Called just prior to starting the message loop
+ virtual void Init() {}
+
+ // Called to start the message loop
+ virtual void Run(MessageLoop* message_loop);
+
+ // Called just after the message loop ends
+ virtual void CleanUp() {}
+
+ // Called after the message loop has been deleted. In general clients
+ // should prefer to use CleanUp(). This method is used when code needs to
+ // be run after all of the MessageLoop::DestructionObservers have completed.
+ virtual void CleanUpAfterMessageLoopDestruction() {}
+
+ static void SetThreadWasQuitProperly(bool flag);
+ static bool GetThreadWasQuitProperly();
+
+ void set_message_loop(MessageLoop* message_loop) {
+ message_loop_ = message_loop;
+ }
+
+ private:
+ bool thread_was_started() const { return started_; }
+
+ // PlatformThread::Delegate methods:
+ virtual void ThreadMain();
+
+ // Whether we successfully started the thread.
+ bool started_;
+
+ // If true, we're in the middle of stopping, and shouldn't access
+ // |message_loop_|. It may non-NULL and invalid.
+ bool stopping_;
+
+ // Used to pass data to ThreadMain.
+ struct StartupData;
+ StartupData* startup_data_;
+
+ // The thread's handle.
+ PlatformThreadHandle thread_;
+
+ // The thread's message loop. Valid only while the thread is alive. Set
+ // by the created thread.
+ MessageLoop* message_loop_;
+
+ // Our thread's ID.
+ PlatformThreadId thread_id_;
+
+ // The name of the thread. Used for debugging purposes.
+ std::string name_;
+
+ friend class ThreadQuitTask;
+
+ DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+} // namespace base
+
+#endif // BASE_THREAD_H_
diff --git a/base/threading/thread_collision_warner.cc b/base/threading/thread_collision_warner.cc
new file mode 100644
index 0000000..547e11c
--- /dev/null
+++ b/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/base/threading/thread_collision_warner.h b/base/threading/thread_collision_warner.h
new file mode 100644
index 0000000..4460602
--- /dev/null
+++ b/base/threading/thread_collision_warner.h
@@ -0,0 +1,244 @@
+// 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_COLLISION_WARNER_H_
+#define BASE_THREADING_THREAD_COLLISION_WARNER_H_
+#pragma once
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/atomicops.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 syncronization) 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)
+#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 {
+ virtual ~DCheckAsserter() {}
+ virtual void warn();
+};
+
+class BASE_EXPORT ThreadCollisionWarner {
+ public:
+ // The parameter asserter is there only for test purpose
+ 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_