summaryrefslogtreecommitdiffstats
path: root/base/threading
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-31 20:02:16 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-31 20:02:16 +0000
commitce072a7181ea5d58133e33654133236f5d9f5551 (patch)
tree1b1c903fec3fd27038cd17cb4ae9ca17d3736e40 /base/threading
parenta8e2058011129cbef38bf89834ee01715556b392 (diff)
downloadchromium_src-ce072a7181ea5d58133e33654133236f5d9f5551.zip
chromium_src-ce072a7181ea5d58133e33654133236f5d9f5551.tar.gz
chromium_src-ce072a7181ea5d58133e33654133236f5d9f5551.tar.bz2
Move platform_thread to base/threading and put in the base namespace. I left a
stub and "using" declarations in the old location to avoid having to change the entire project at once. TEST=it compiles BUG=none Review URL: http://codereview.chromium.org/6001010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70342 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/threading')
-rw-r--r--base/threading/platform_thread.h99
-rw-r--r--base/threading/platform_thread_mac.mm54
-rw-r--r--base/threading/platform_thread_posix.cc225
-rw-r--r--base/threading/platform_thread_unittest.cc106
-rw-r--r--base/threading/platform_thread_win.cc147
-rw-r--r--base/threading/simple_thread.cc2
-rw-r--r--base/threading/simple_thread.h2
-rw-r--r--base/threading/thread_checker.cc38
-rw-r--r--base/threading/thread_checker.h73
-rw-r--r--base/threading/thread_checker_unittest.cc146
-rw-r--r--base/threading/watchdog.cc2
-rw-r--r--base/threading/watchdog.h2
-rw-r--r--base/threading/watchdog_unittest.cc2
-rw-r--r--base/threading/worker_pool_posix.cc2
-rw-r--r--base/threading/worker_pool_posix.h2
-rw-r--r--base/threading/worker_pool_posix_unittest.cc2
16 files changed, 896 insertions, 8 deletions
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
new file mode 100644
index 0000000..0a3c75d7
--- /dev/null
+++ b/base/threading/platform_thread.h
@@ -0,0 +1,99 @@
+// 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.
+
+// 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/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;
+
+// A namespace for low-level thread functions.
+class PlatformThread {
+ public:
+ // Implement this interface to run code on a background thread. Your
+ // ThreadMain method will be called on the newly created thread.
+ class 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 a debugger. This has no effect otherwise.
+ static void SetName(const char* name);
+
+ // 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);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_PLATFORM_THREAD_H_
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
new file mode 100644
index 0000000..d77307c5
--- /dev/null
+++ b/base/threading/platform_thread_mac.mm
@@ -0,0 +1,54 @@
+// 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/platform_thread.h"
+
+#import <Foundation/Foundation.h>
+#include <dlfcn.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// If Cocoa is to be used on more than one thread, it must know that the
+// application is multithreaded. Since it's possible to enter Cocoa code
+// from threads created by pthread_thread_create, Cocoa won't necessarily
+// be aware that the application is multithreaded. Spawning an NSThread is
+// enough to get Cocoa to set up for multithreaded operation, so this is done
+// if necessary before pthread_thread_create spawns any threads.
+//
+// http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/chapter_4_section_4.html
+void InitThreading() {
+ static BOOL multithreaded = [NSThread isMultiThreaded];
+ if (!multithreaded) {
+ // +[NSObject class] is idempotent.
+ [NSThread detachNewThreadSelector:@selector(class)
+ toTarget:[NSObject class]
+ withObject:nil];
+ multithreaded = YES;
+
+ DCHECK([NSThread isMultiThreaded]);
+ }
+}
+
+// static
+void PlatformThread::SetName(const char* name) {
+ // pthread_setname_np is only available in 10.6 or later, so test
+ // for it at runtime.
+ int (*dynamic_pthread_setname_np)(const char*);
+ *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
+ dlsym(RTLD_DEFAULT, "pthread_setname_np");
+ if (!dynamic_pthread_setname_np)
+ return;
+
+ // Mac OS X does not expose the length limit of the name, so
+ // hardcode it.
+ const int kMaxNameLength = 63;
+ std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
+ // pthread_setname() fails (harmlessly) in the sandbox, ignore when it does.
+ // See http://crbug.com/47058
+ dynamic_pthread_setname_np(shortened_name.c_str());
+}
+
+} // namespace base
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
new file mode 100644
index 0000000..0ef4990
--- /dev/null
+++ b/base/threading/platform_thread_posix.cc
@@ -0,0 +1,225 @@
+// 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/platform_thread.h"
+
+#include <errno.h>
+#include <sched.h>
+
+#include "base/logging.h"
+#include "base/safe_strerror_posix.h"
+#include "base/scoped_ptr.h"
+#include "base/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_NACL)
+#include <sys/nacl_syscalls.h>
+#endif
+
+namespace base {
+
+#if defined(OS_MACOSX)
+void InitThreading();
+#endif
+
+namespace {
+
+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();
+ 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_FREEBSD)
+ // TODO(BSD): find a better thread ID
+ return reinterpret_cast<int64>(pthread_self());
+#elif defined(OS_NACL)
+ 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) {
+ // 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) {
+ // Leave it unimplemented.
+
+ // (This should be relatively simple to implement for the BSDs; I
+ // just don't have one handy to test the code on.)
+}
+#endif // defined(OS_LINUX)
+
+// static
+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);
+}
+
+} // namespace base
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
new file mode 100644
index 0000000..4b49450
--- /dev/null
+++ b/base/threading/platform_thread_unittest.cc
@@ -0,0 +1,106 @@
+// 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/platform_thread.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Trivial tests that thread runs and doesn't crash on create and join ---------
+
+class TrivialThread : public PlatformThread::Delegate {
+ public:
+ TrivialThread() : did_run_(false) {}
+
+ virtual void ThreadMain() {
+ did_run_ = true;
+ }
+
+ bool did_run() const { return did_run_; }
+
+ private:
+ bool did_run_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrivialThread);
+};
+
+TEST(PlatformThreadTest, Trivial) {
+ TrivialThread thread;
+ PlatformThreadHandle handle = kNullThreadHandle;
+
+ ASSERT_FALSE(thread.did_run());
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+ PlatformThread::Join(handle);
+ ASSERT_TRUE(thread.did_run());
+}
+
+TEST(PlatformThreadTest, TrivialTimesTen) {
+ TrivialThread thread[10];
+ PlatformThreadHandle handle[arraysize(thread)];
+
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_FALSE(thread[n].did_run());
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+ for (size_t n = 0; n < arraysize(thread); n++)
+ PlatformThread::Join(handle[n]);
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_TRUE(thread[n].did_run());
+}
+
+// Tests of basic thread functions ---------------------------------------------
+
+class FunctionTestThread : public TrivialThread {
+ public:
+ FunctionTestThread() : thread_id_(0) {}
+
+ virtual void ThreadMain() {
+ thread_id_ = PlatformThread::CurrentId();
+ PlatformThread::YieldCurrentThread();
+ PlatformThread::Sleep(50);
+
+ TrivialThread::ThreadMain();
+ }
+
+ PlatformThreadId thread_id() const { return thread_id_; }
+
+ private:
+ PlatformThreadId thread_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
+};
+
+TEST(PlatformThreadTest, Function) {
+ PlatformThreadId main_thread_id = PlatformThread::CurrentId();
+
+ FunctionTestThread thread;
+ PlatformThreadHandle handle = kNullThreadHandle;
+
+ ASSERT_FALSE(thread.did_run());
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+ PlatformThread::Join(handle);
+ ASSERT_TRUE(thread.did_run());
+ EXPECT_NE(thread.thread_id(), main_thread_id);
+}
+
+TEST(PlatformThreadTest, FunctionTimesTen) {
+ PlatformThreadId main_thread_id = PlatformThread::CurrentId();
+
+ FunctionTestThread thread[10];
+ PlatformThreadHandle handle[arraysize(thread)];
+
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_FALSE(thread[n].did_run());
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+ for (size_t n = 0; n < arraysize(thread); n++)
+ PlatformThread::Join(handle[n]);
+ for (size_t n = 0; n < arraysize(thread); n++) {
+ ASSERT_TRUE(thread[n].did_run());
+ EXPECT_NE(thread[n].thread_id(), main_thread_id);
+ }
+}
+
+} // namespace base
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
new file mode 100644
index 0000000..10f3011
--- /dev/null
+++ b/base/threading/platform_thread_win.cc
@@ -0,0 +1,147 @@
+// 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/platform_thread.h"
+
+#include "base/logging.h"
+#include "base/thread_restrictions.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;
+
+struct ThreadParams {
+ PlatformThread::Delegate* delegate;
+ bool joinable;
+};
+
+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);
+ delete thread_params;
+ delegate->ThreadMain();
+ return NULL;
+}
+
+// CreateThreadInternal() matches PlatformThread::Create(), except that
+// |out_thread_handle| may be NULL, in which case a non-joinable thread is
+// created.
+bool CreateThreadInternal(size_t stack_size,
+ PlatformThread::Delegate* delegate,
+ PlatformThreadHandle* out_thread_handle) {
+ PlatformThreadHandle thread_handle;
+ unsigned int flags = 0;
+ if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
+ flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
+ } else {
+ stack_size = 0;
+ }
+
+ ThreadParams* params = new ThreadParams;
+ params->delegate = delegate;
+ params->joinable = out_thread_handle != NULL;
+
+ // 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
+ thread_handle = CreateThread(
+ NULL, stack_size, ThreadFunc, params, flags, NULL);
+ if (!thread_handle) {
+ delete params;
+ return false;
+ }
+
+ if (out_thread_handle)
+ *out_thread_handle = thread_handle;
+ else
+ CloseHandle(thread_handle);
+ return true;
+}
+
+} // namespace
+
+// static
+PlatformThreadId PlatformThread::CurrentId() {
+ return GetCurrentThreadId();
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+ ::Sleep(0);
+}
+
+// static
+void PlatformThread::Sleep(int duration_ms) {
+ ::Sleep(duration_ms);
+}
+
+// static
+void PlatformThread::SetName(const char* 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 (!::IsDebuggerPresent())
+ return;
+
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = CurrentId();
+ info.dwFlags = 0;
+
+ __try {
+ RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
+ reinterpret_cast<DWORD_PTR*>(&info));
+ } __except(EXCEPTION_CONTINUE_EXECUTION) {
+ }
+}
+
+// static
+bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
+ PlatformThreadHandle* thread_handle) {
+ DCHECK(thread_handle);
+ return CreateThreadInternal(stack_size, delegate, thread_handle);
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+ return CreateThreadInternal(stack_size, delegate, NULL);
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+ DCHECK(thread_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, INFINITE);
+ DCHECK_EQ(WAIT_OBJECT_0, result);
+
+ CloseHandle(thread_handle);
+}
+
+} // namespace base
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
index df1953f..2b030f6 100644
--- a/base/threading/simple_thread.cc
+++ b/base/threading/simple_thread.cc
@@ -5,7 +5,7 @@
#include "base/threading/simple_thread.h"
#include "base/logging.h"
-#include "base/platform_thread.h"
+#include "base/threading/platform_thread.h"
#include "base/string_number_conversions.h"
namespace base {
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
index dbff3ae..c401e01 100644
--- a/base/threading/simple_thread.h
+++ b/base/threading/simple_thread.h
@@ -47,8 +47,8 @@
#include "base/basictypes.h"
#include "base/lock.h"
+#include "base/threading/platform_thread.h"
#include "base/waitable_event.h"
-#include "base/platform_thread.h"
namespace base {
diff --git a/base/threading/thread_checker.cc b/base/threading/thread_checker.cc
new file mode 100644
index 0000000..28ba400
--- /dev/null
+++ b/base/threading/thread_checker.cc
@@ -0,0 +1,38 @@
+// 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_checker.h"
+
+// This code is only done in debug builds.
+#ifndef NDEBUG
+
+namespace base {
+
+ThreadChecker::ThreadChecker() : valid_thread_id_(kInvalidThreadId) {
+ EnsureThreadIdAssigned();
+}
+
+ThreadChecker::~ThreadChecker() {}
+
+bool ThreadChecker::CalledOnValidThread() const {
+ EnsureThreadIdAssigned();
+ AutoLock auto_lock(lock_);
+ return valid_thread_id_ == PlatformThread::CurrentId();
+}
+
+void ThreadChecker::DetachFromThread() {
+ AutoLock auto_lock(lock_);
+ valid_thread_id_ = kInvalidThreadId;
+}
+
+void ThreadChecker::EnsureThreadIdAssigned() const {
+ AutoLock auto_lock(lock_);
+ if (valid_thread_id_ != kInvalidThreadId)
+ return;
+ valid_thread_id_ = PlatformThread::CurrentId();
+}
+
+} // namespace base
+
+#endif // NDEBUG
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
new file mode 100644
index 0000000..c0010fb
--- /dev/null
+++ b/base/threading/thread_checker.h
@@ -0,0 +1,73 @@
+// 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.
+
+#ifndef BASE_THREADING_THREAD_CHECKER_H_
+#define BASE_THREADING_THREAD_CHECKER_H_
+#pragma once
+
+#ifndef NDEBUG
+#include "base/lock.h"
+#include "base/threading/platform_thread.h"
+#endif // NDEBUG
+
+namespace base {
+
+// Before using this class, please consider using NonThreadSafe as it
+// makes it much easier to determine the nature of your class.
+//
+// A helper class used to help verify that some methods of a class are
+// called from the same thread. One can inherit from this class and use
+// CalledOnValidThread() to verify.
+//
+// Inheriting from class indicates that one must be careful when using the class
+// with multiple threads. However, it is up to the class document to indicate
+// how it can be used with threads.
+//
+// Example:
+// class MyClass : public ThreadChecker {
+// public:
+// void Foo() {
+// DCHECK(CalledOnValidThread());
+// ... (do stuff) ...
+// }
+// }
+//
+// In Release mode, CalledOnValidThread will always return true.
+//
+#ifndef NDEBUG
+class ThreadChecker {
+ public:
+ ThreadChecker();
+ ~ThreadChecker();
+
+ bool CalledOnValidThread() const;
+
+ // 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 Lock lock_;
+ // This is mutable so that CalledOnValidThread can set it.
+ // It's guarded by |lock_|.
+ mutable PlatformThreadId valid_thread_id_;
+};
+#else
+// Do nothing in release mode.
+class ThreadChecker {
+ public:
+ bool CalledOnValidThread() const {
+ return true;
+ }
+
+ void DetachFromThread() {}
+};
+#endif // NDEBUG
+
+} // namespace base
+
+#endif // BASE_THREADING_THREAD_CHECKER_H_
diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc
new file mode 100644
index 0000000..6ce5bf1
--- /dev/null
+++ b/base/threading/thread_checker_unittest.cc
@@ -0,0 +1,146 @@
+// 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/basictypes.h"
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#ifndef NDEBUG
+
+namespace base {
+
+// Simple class to exersice the basics of ThreadChecker.
+// Both the destructor and DoStuff should verify that they were
+// called on the same thread as the constructor.
+class ThreadCheckerClass : public ThreadChecker {
+ public:
+ ThreadCheckerClass() {}
+
+ // Verifies that it was called on the same thread as the constructor.
+ void DoStuff() {
+ DCHECK(CalledOnValidThread());
+ }
+
+ void DetachFromThread() {
+ ThreadChecker::DetachFromThread();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
+};
+
+// Calls ThreadCheckerClass::DoStuff on another thread.
+class CallDoStuffOnThread : public base::SimpleThread {
+ public:
+ CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
+ : SimpleThread("call_do_stuff_on_thread"),
+ thread_checker_class_(thread_checker_class) {
+ }
+
+ virtual void Run() {
+ thread_checker_class_->DoStuff();
+ }
+
+ private:
+ ThreadCheckerClass* thread_checker_class_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
+};
+
+// Deletes ThreadCheckerClass on a different thread.
+class DeleteThreadCheckerClassOnThread : public base::SimpleThread {
+ public:
+ DeleteThreadCheckerClassOnThread(ThreadCheckerClass* thread_checker_class)
+ : SimpleThread("delete_thread_checker_class_on_thread"),
+ thread_checker_class_(thread_checker_class) {
+ }
+
+ virtual void Run() {
+ thread_checker_class_.reset();
+ }
+
+ private:
+ scoped_ptr<ThreadCheckerClass> thread_checker_class_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
+};
+
+TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
+ scoped_ptr<ThreadCheckerClass> thread_checker_class(
+ new ThreadCheckerClass);
+
+ // Verify that DoStuff doesn't assert.
+ thread_checker_class->DoStuff();
+
+ // Verify that the destructor doesn't assert.
+ thread_checker_class.reset();
+}
+
+TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
+ scoped_ptr<ThreadCheckerClass> thread_checker_class(
+ new ThreadCheckerClass);
+
+ // Verify that the destructor doesn't assert
+ // when called on a different thread.
+ DeleteThreadCheckerClassOnThread delete_on_thread(
+ thread_checker_class.release());
+
+ delete_on_thread.Start();
+ delete_on_thread.Join();
+}
+
+TEST(ThreadCheckerTest, DetachFromThread) {
+ scoped_ptr<ThreadCheckerClass> thread_checker_class(
+ new ThreadCheckerClass);
+
+ // Verify that DoStuff doesn't assert when called on a different thread after
+ // a call to DetachFromThread.
+ thread_checker_class->DetachFromThread();
+ CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+ call_on_thread.Start();
+ call_on_thread.Join();
+}
+
+#if GTEST_HAS_DEATH_TEST
+
+TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThread) {
+ ASSERT_DEBUG_DEATH({
+ scoped_ptr<ThreadCheckerClass> thread_checker_class(
+ new ThreadCheckerClass);
+
+ // Verify that DoStuff asserts when called on a different thread.
+ CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+ call_on_thread.Start();
+ call_on_thread.Join();
+ }, "");
+}
+
+TEST(ThreadCheckerDeathTest, DetachFromThread) {
+ ASSERT_DEBUG_DEATH({
+ scoped_ptr<ThreadCheckerClass> thread_checker_class(
+ new ThreadCheckerClass);
+
+ // Verify that DoStuff doesn't assert when called on a different thread
+ // after a call to DetachFromThread.
+ thread_checker_class->DetachFromThread();
+ CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+ call_on_thread.Start();
+ call_on_thread.Join();
+
+ // Verify that DoStuff asserts after moving to another thread.
+ thread_checker_class->DoStuff();
+ }, "");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace base
+
+#endif // NDEBUG
diff --git a/base/threading/watchdog.cc b/base/threading/watchdog.cc
index 8474744..cd21578 100644
--- a/base/threading/watchdog.cc
+++ b/base/threading/watchdog.cc
@@ -6,7 +6,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
-#include "base/platform_thread.h"
+#include "base/threading/platform_thread.h"
namespace base {
diff --git a/base/threading/watchdog.h b/base/threading/watchdog.h
index 025fe09..8641f04 100644
--- a/base/threading/watchdog.h
+++ b/base/threading/watchdog.h
@@ -23,7 +23,7 @@
#include "base/condition_variable.h"
#include "base/lock.h"
-#include "base/platform_thread.h"
+#include "base/threading/platform_thread.h"
#include "base/time.h"
namespace base {
diff --git a/base/threading/watchdog_unittest.cc b/base/threading/watchdog_unittest.cc
index 347781e..f96487b 100644
--- a/base/threading/watchdog_unittest.cc
+++ b/base/threading/watchdog_unittest.cc
@@ -5,8 +5,8 @@
#include "base/threading/watchdog.h"
#include "base/logging.h"
-#include "base/platform_thread.h"
#include "base/spin_wait.h"
+#include "base/threading/platform_thread.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/threading/worker_pool_posix.cc b/base/threading/worker_pool_posix.cc
index 2facc01..8466403 100644
--- a/base/threading/worker_pool_posix.cc
+++ b/base/threading/worker_pool_posix.cc
@@ -6,10 +6,10 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/platform_thread.h"
#include "base/ref_counted.h"
#include "base/stringprintf.h"
#include "base/task.h"
+#include "base/threading/platform_thread.h"
#include "base/threading/worker_pool.h"
namespace base {
diff --git a/base/threading/worker_pool_posix.h b/base/threading/worker_pool_posix.h
index 6c99e76..44f0208 100644
--- a/base/threading/worker_pool_posix.h
+++ b/base/threading/worker_pool_posix.h
@@ -31,9 +31,9 @@
#include "base/basictypes.h"
#include "base/condition_variable.h"
#include "base/lock.h"
-#include "base/platform_thread.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/threading/platform_thread.h"
class Task;
diff --git a/base/threading/worker_pool_posix_unittest.cc b/base/threading/worker_pool_posix_unittest.cc
index 48df16e..25509bf 100644
--- a/base/threading/worker_pool_posix_unittest.cc
+++ b/base/threading/worker_pool_posix_unittest.cc
@@ -8,8 +8,8 @@
#include "base/condition_variable.h"
#include "base/lock.h"
-#include "base/platform_thread.h"
#include "base/task.h"
+#include "base/threading/platform_thread.h"
#include "base/waitable_event.h"
#include "testing/gtest/include/gtest/gtest.h"