2014-06-16 11:34:44 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
|
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Borrowed from Chromium's src/base/threading/thread_checker_unittest.cc.
|
|
|
|
|
|
2016-04-26 03:13:22 -07:00
|
|
|
#include <memory>
|
|
|
|
|
|
2014-06-16 11:34:44 +00:00
|
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
2014-09-15 11:19:35 +00:00
|
|
|
#include "webrtc/base/checks.h"
|
2016-04-26 08:14:39 -07:00
|
|
|
#include "webrtc/base/constructormagic.h"
|
2014-06-16 11:34:44 +00:00
|
|
|
#include "webrtc/base/thread.h"
|
|
|
|
|
#include "webrtc/base/thread_checker.h"
|
|
|
|
|
|
|
|
|
|
// Duplicated from base/threading/thread_checker.h so that we can be
|
|
|
|
|
// good citizens there and undef the macro.
|
|
|
|
|
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
|
|
|
|
#define ENABLE_THREAD_CHECKER 1
|
|
|
|
|
#else
|
|
|
|
|
#define ENABLE_THREAD_CHECKER 0
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
namespace rtc {
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
// Simple class to exercise 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.
|
2015-09-17 00:24:34 -07:00
|
|
|
void DoStuff() { RTC_DCHECK(CalledOnValidThread()); }
|
2014-06-16 11:34:44 +00:00
|
|
|
|
|
|
|
|
void DetachFromThread() {
|
|
|
|
|
ThreadChecker::DetachFromThread();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void MethodOnDifferentThreadImpl();
|
|
|
|
|
static void DetachThenCallFromDifferentThreadImpl();
|
|
|
|
|
|
|
|
|
|
private:
|
2015-09-16 05:37:44 -07:00
|
|
|
RTC_DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
|
2014-06-16 11:34:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Calls ThreadCheckerClass::DoStuff on another thread.
|
|
|
|
|
class CallDoStuffOnThread : public Thread {
|
|
|
|
|
public:
|
|
|
|
|
explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
|
|
|
|
|
: Thread(),
|
|
|
|
|
thread_checker_class_(thread_checker_class) {
|
|
|
|
|
SetName("call_do_stuff_on_thread", NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void Run() override { thread_checker_class_->DoStuff(); }
|
2014-06-16 11:34:44 +00:00
|
|
|
|
|
|
|
|
// New method. Needed since Thread::Join is protected, and it is called by
|
|
|
|
|
// the TEST.
|
|
|
|
|
void Join() {
|
|
|
|
|
Thread::Join();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
ThreadCheckerClass* thread_checker_class_;
|
|
|
|
|
|
2015-09-16 05:37:44 -07:00
|
|
|
RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
|
2014-06-16 11:34:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Deletes ThreadCheckerClass on a different thread.
|
|
|
|
|
class DeleteThreadCheckerClassOnThread : public Thread {
|
|
|
|
|
public:
|
|
|
|
|
explicit DeleteThreadCheckerClassOnThread(
|
|
|
|
|
ThreadCheckerClass* thread_checker_class)
|
|
|
|
|
: Thread(),
|
|
|
|
|
thread_checker_class_(thread_checker_class) {
|
|
|
|
|
SetName("delete_thread_checker_class_on_thread", NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void Run() override { thread_checker_class_.reset(); }
|
2014-06-16 11:34:44 +00:00
|
|
|
|
|
|
|
|
// New method. Needed since Thread::Join is protected, and it is called by
|
|
|
|
|
// the TEST.
|
|
|
|
|
void Join() {
|
|
|
|
|
Thread::Join();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2016-04-26 03:13:22 -07:00
|
|
|
std::unique_ptr<ThreadCheckerClass> thread_checker_class_;
|
2014-06-16 11:34:44 +00:00
|
|
|
|
2015-09-16 05:37:44 -07:00
|
|
|
RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
|
2014-06-16 11:34:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
2014-10-09 22:08:15 +00:00
|
|
|
TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
|
2016-04-26 03:13:22 -07:00
|
|
|
std::unique_ptr<ThreadCheckerClass> thread_checker_class(
|
2014-06-16 11:34:44 +00:00
|
|
|
new ThreadCheckerClass);
|
|
|
|
|
|
|
|
|
|
// Verify that DoStuff doesn't assert.
|
|
|
|
|
thread_checker_class->DoStuff();
|
|
|
|
|
|
|
|
|
|
// Verify that the destructor doesn't assert.
|
|
|
|
|
thread_checker_class.reset();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-09 22:08:15 +00:00
|
|
|
TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
|
2016-04-26 03:13:22 -07:00
|
|
|
std::unique_ptr<ThreadCheckerClass> thread_checker_class(
|
2014-06-16 11:34:44 +00:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-09 22:08:15 +00:00
|
|
|
TEST(ThreadCheckerTest, DetachFromThread) {
|
2016-04-26 03:13:22 -07:00
|
|
|
std::unique_ptr<ThreadCheckerClass> thread_checker_class(
|
2014-06-16 11:34:44 +00:00
|
|
|
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 || !ENABLE_THREAD_CHECKER
|
|
|
|
|
|
|
|
|
|
void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
|
2016-04-26 03:13:22 -07:00
|
|
|
std::unique_ptr<ThreadCheckerClass> thread_checker_class(
|
2014-06-16 11:34:44 +00:00
|
|
|
new ThreadCheckerClass);
|
|
|
|
|
|
|
|
|
|
// DoStuff should assert in debug builds only when called on a
|
|
|
|
|
// different thread.
|
|
|
|
|
CallDoStuffOnThread call_on_thread(thread_checker_class.get());
|
|
|
|
|
|
|
|
|
|
call_on_thread.Start();
|
|
|
|
|
call_on_thread.Join();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if ENABLE_THREAD_CHECKER
|
Switch ThreadCheckerImpl over to using PlatformThreadRef.
Like PlatformThreadId, this type is borrowed from Chromium.
The difference between the two is that PlatformThreadRef is pthread_t on posix platforms.
On Windows PlatformThreadRef and PlatformThreadId are the same thing.
The reason for this switch is pretty crazy. On Chromium's "Mac 10.9 dbg" bot,
we have been seeing the following code:
ThreadCheckerImpl::ThreadCheckerImpl() : valid_thread_(CurrentThreadId()) {
fprintf(stderr, "*** valid=%d\n", valid_thread_);
valid_thread_ = CurrentThreadId();
fprintf(stderr, "*** valid after=%d\n", valid_thread_);
}
print this:
*** valid=946872320
*** valid after=5647
This is for the same thread checker instance.
What's worse is that printing out what CurrentThreadId was returning, yielded that it was always returning 5647.
After switching over to pthread_t on Mac, this stopped happening.
So, to remove the current hack, reinstate the class on Mac and take a look at the next problem, I'm switching to pthread_t.
Really looking forward to truly getting to the bottom of this.
Tbr-ing since the build is essentially broken (we can't roll).
TBR=pbos@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/37199004
Cr-Commit-Position: refs/heads/master@{#8283}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8283 4adac7df-926f-26a2-2b94-8c16560cd09d
2015-02-07 19:17:47 +00:00
|
|
|
TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
|
2014-06-16 11:34:44 +00:00
|
|
|
ASSERT_DEATH({
|
|
|
|
|
ThreadCheckerClass::MethodOnDifferentThreadImpl();
|
|
|
|
|
}, "");
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
|
|
|
|
|
ThreadCheckerClass::MethodOnDifferentThreadImpl();
|
|
|
|
|
}
|
|
|
|
|
#endif // ENABLE_THREAD_CHECKER
|
|
|
|
|
|
|
|
|
|
void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
|
2016-04-26 03:13:22 -07:00
|
|
|
std::unique_ptr<ThreadCheckerClass> thread_checker_class(
|
2014-06-16 11:34:44 +00:00
|
|
|
new ThreadCheckerClass);
|
|
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
|
|
|
|
|
// DoStuff should assert in debug builds only after moving to
|
|
|
|
|
// another thread.
|
|
|
|
|
thread_checker_class->DoStuff();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if ENABLE_THREAD_CHECKER
|
Switch ThreadCheckerImpl over to using PlatformThreadRef.
Like PlatformThreadId, this type is borrowed from Chromium.
The difference between the two is that PlatformThreadRef is pthread_t on posix platforms.
On Windows PlatformThreadRef and PlatformThreadId are the same thing.
The reason for this switch is pretty crazy. On Chromium's "Mac 10.9 dbg" bot,
we have been seeing the following code:
ThreadCheckerImpl::ThreadCheckerImpl() : valid_thread_(CurrentThreadId()) {
fprintf(stderr, "*** valid=%d\n", valid_thread_);
valid_thread_ = CurrentThreadId();
fprintf(stderr, "*** valid after=%d\n", valid_thread_);
}
print this:
*** valid=946872320
*** valid after=5647
This is for the same thread checker instance.
What's worse is that printing out what CurrentThreadId was returning, yielded that it was always returning 5647.
After switching over to pthread_t on Mac, this stopped happening.
So, to remove the current hack, reinstate the class on Mac and take a look at the next problem, I'm switching to pthread_t.
Really looking forward to truly getting to the bottom of this.
Tbr-ing since the build is essentially broken (we can't roll).
TBR=pbos@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/37199004
Cr-Commit-Position: refs/heads/master@{#8283}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8283 4adac7df-926f-26a2-2b94-8c16560cd09d
2015-02-07 19:17:47 +00:00
|
|
|
TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
|
2014-06-16 11:34:44 +00:00
|
|
|
ASSERT_DEATH({
|
|
|
|
|
ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
|
|
|
|
|
}, "");
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
|
|
|
|
|
ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
|
|
|
|
|
}
|
|
|
|
|
#endif // ENABLE_THREAD_CHECKER
|
|
|
|
|
|
|
|
|
|
#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
|
|
|
|
|
|
|
|
|
|
// Just in case we ever get lumped together with other compilation units.
|
|
|
|
|
#undef ENABLE_THREAD_CHECKER
|
|
|
|
|
|
|
|
|
|
} // namespace rtc
|