1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
23345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Use of this source code is governed by a BSD-style license that can be
33345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// found in the LICENSE file.
43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
53345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/basictypes.h"
63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/logging.h"
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_checker.h"
93f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/simple_thread.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "testing/gtest/include/gtest/gtest.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace base {
133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
14dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Simple class to exercise the basics of ThreadChecker.
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Both the destructor and DoStuff should verify that they were
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// called on the same thread as the constructor.
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass ThreadCheckerClass : public ThreadChecker {
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ThreadCheckerClass() {}
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Verifies that it was called on the same thread as the constructor.
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void DoStuff() {
23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    CHECK(CalledOnValidThread());
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
26731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  void DetachFromThread() {
27731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    ThreadChecker::DetachFromThread();
28731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
29731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  static void MethodOnDifferentThreadImpl();
31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  static void DetachThenCallFromDifferentThreadImpl();
32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Calls ThreadCheckerClass::DoStuff on another thread.
383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass CallDoStuffOnThread : public base::SimpleThread {
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      : SimpleThread("call_do_stuff_on_thread"),
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        thread_checker_class_(thread_checker_class) {
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void Run() {
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    thread_checker_class_->DoStuff();
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ThreadCheckerClass* thread_checker_class_;
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Deletes ThreadCheckerClass on a different thread.
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass DeleteThreadCheckerClassOnThread : public base::SimpleThread {
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DeleteThreadCheckerClassOnThread(ThreadCheckerClass* thread_checker_class)
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      : SimpleThread("delete_thread_checker_class_on_thread"),
603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        thread_checker_class_(thread_checker_class) {
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void Run() {
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    thread_checker_class_.reset();
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<ThreadCheckerClass> thread_checker_class_;
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickTEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<ThreadCheckerClass> thread_checker_class(
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      new ThreadCheckerClass);
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Verify that DoStuff doesn't assert.
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  thread_checker_class->DoStuff();
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Verify that the destructor doesn't assert.
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  thread_checker_class.reset();
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickTEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<ThreadCheckerClass> thread_checker_class(
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      new ThreadCheckerClass);
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Verify that the destructor doesn't assert
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // when called on a different thread.
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DeleteThreadCheckerClassOnThread delete_on_thread(
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      thread_checker_class.release());
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  delete_on_thread.Start();
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  delete_on_thread.Join();
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
97731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickTEST(ThreadCheckerTest, DetachFromThread) {
98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  scoped_ptr<ThreadCheckerClass> thread_checker_class(
99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      new ThreadCheckerClass);
100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
101731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Verify that DoStuff doesn't assert when called on a different thread after
102731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // a call to DetachFromThread.
103731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  thread_checker_class->DetachFromThread();
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  call_on_thread.Start();
107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  call_on_thread.Join();
108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
110dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if GTEST_HAS_DEATH_TEST || NDEBUG
1113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid ThreadCheckerClass::MethodOnDifferentThreadImpl() {
113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  scoped_ptr<ThreadCheckerClass> thread_checker_class(
114dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      new ThreadCheckerClass);
1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // DoStuff should assert in debug builds only when called on a
117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // different thread.
118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  call_on_thread.Start();
121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  call_on_thread.Join();
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#ifndef NDEBUG
125dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenTEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  ASSERT_DEBUG_DEATH({
127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      ThreadCheckerClass::MethodOnDifferentThreadImpl();
128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }, "");
129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#else
131dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenTEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ThreadCheckerClass::MethodOnDifferentThreadImpl();
133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif  // NDEBUG
135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  scoped_ptr<ThreadCheckerClass> thread_checker_class(
138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      new ThreadCheckerClass);
139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // DoStuff doesn't assert when called on a different thread
141dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // after a call to DetachFromThread.
142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  thread_checker_class->DetachFromThread();
143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
144731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  call_on_thread.Start();
146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  call_on_thread.Join();
147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // DoStuff should assert in debug builds only after moving to
149dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // another thread.
150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  thread_checker_class->DoStuff();
151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
152dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
153dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#ifndef NDEBUG
154dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenTEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
155dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ASSERT_DEBUG_DEATH({
156dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }, "");
158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#else
160dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenTEST(ThreadCheckerTest, DetachFromThreadInRelease) {
161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
162dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
163dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif  // NDEBUG
164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
165dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif  // GTEST_HAS_DEATH_TEST || NDEBUG
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace base
168