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>
|
|
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "rtc_base/checks.h"
|
|
|
|
|
#include "rtc_base/constructormagic.h"
|
|
|
|
|
#include "rtc_base/nullsocketserver.h"
|
|
|
|
|
#include "rtc_base/task_queue.h"
|
|
|
|
|
#include "rtc_base/thread.h"
|
|
|
|
|
#include "rtc_base/thread_checker.h"
|
|
|
|
|
#include "test/gtest.h"
|
2014-06-16 11:34:44 +00:00
|
|
|
|
|
|
|
|
// Duplicated from base/threading/thread_checker.h so that we can be
|
|
|
|
|
// good citizens there and undef the macro.
|
2016-10-04 13:46:56 -07:00
|
|
|
#define ENABLE_THREAD_CHECKER RTC_DCHECK_IS_ON
|
2014-06-16 11:34:44 +00:00
|
|
|
|
|
|
|
|
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)
|
2017-07-14 14:44:46 -07:00
|
|
|
: Thread(std::unique_ptr<SocketServer>(new rtc::NullSocketServer())),
|
2014-06-16 11:34:44 +00:00
|
|
|
thread_checker_class_(thread_checker_class) {
|
2017-02-27 14:06:41 -08:00
|
|
|
SetName("call_do_stuff_on_thread", nullptr);
|
2014-06-16 11:34:44 +00:00
|
|
|
}
|
|
|
|
|
|
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(
|
2017-07-14 14:44:46 -07:00
|
|
|
std::unique_ptr<ThreadCheckerClass> thread_checker_class)
|
|
|
|
|
: Thread(std::unique_ptr<SocketServer>(new rtc::NullSocketServer())),
|
|
|
|
|
thread_checker_class_(std::move(thread_checker_class)) {
|
2017-02-27 14:06:41 -08:00
|
|
|
SetName("delete_thread_checker_class_on_thread", nullptr);
|
2014-06-16 11:34:44 +00:00
|
|
|
}
|
|
|
|
|
|
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(); }
|
|
|
|
|
|
2017-07-14 14:44:46 -07:00
|
|
|
bool has_been_deleted() const { return !thread_checker_class_; }
|
|
|
|
|
|
2014-06-16 11:34:44 +00:00
|
|
|
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(
|
2017-07-14 14:44:46 -07:00
|
|
|
std::move(thread_checker_class));
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(delete_on_thread.has_been_deleted());
|
2014-06-16 11:34:44 +00:00
|
|
|
|
|
|
|
|
delete_on_thread.Start();
|
|
|
|
|
delete_on_thread.Join();
|
2017-07-14 14:44:46 -07:00
|
|
|
|
|
|
|
|
EXPECT_TRUE(delete_on_thread.has_been_deleted());
|
2014-06-16 11:34:44 +00:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
|
2016-05-19 06:49:03 -07:00
|
|
|
class ThreadAnnotateTest {
|
|
|
|
|
public:
|
|
|
|
|
// Next two function should create warnings when compile (e.g. if used with
|
|
|
|
|
// specific T).
|
|
|
|
|
// TODO(danilchap): Find a way to test they do not compile when thread
|
|
|
|
|
// annotation checks enabled.
|
|
|
|
|
template <typename T>
|
|
|
|
|
void access_var_no_annotate() {
|
|
|
|
|
var_thread_ = 42;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
void access_fun_no_annotate() {
|
|
|
|
|
function();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Functions below should be able to compile.
|
|
|
|
|
void access_var_annotate_thread() {
|
|
|
|
|
RTC_DCHECK_RUN_ON(thread_);
|
|
|
|
|
var_thread_ = 42;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void access_var_annotate_checker() {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&checker_);
|
|
|
|
|
var_checker_ = 44;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void access_var_annotate_queue() {
|
|
|
|
|
RTC_DCHECK_RUN_ON(queue_);
|
|
|
|
|
var_queue_ = 46;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void access_fun_annotate() {
|
|
|
|
|
RTC_DCHECK_RUN_ON(thread_);
|
|
|
|
|
function();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void access_fun_and_var() {
|
|
|
|
|
RTC_DCHECK_RUN_ON(thread_);
|
|
|
|
|
fun_acccess_var();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2017-09-06 04:10:21 -07:00
|
|
|
void function() RTC_RUN_ON(thread_) {}
|
|
|
|
|
void fun_acccess_var() RTC_RUN_ON(thread_) { var_thread_ = 13; }
|
2016-05-19 06:49:03 -07:00
|
|
|
|
|
|
|
|
rtc::Thread* thread_;
|
|
|
|
|
rtc::ThreadChecker checker_;
|
|
|
|
|
rtc::TaskQueue* queue_;
|
|
|
|
|
|
2018-02-07 10:18:32 +01:00
|
|
|
int var_thread_ RTC_GUARDED_BY(thread_);
|
2017-09-06 04:10:21 -07:00
|
|
|
int var_checker_ RTC_GUARDED_BY(checker_);
|
2018-02-07 10:18:32 +01:00
|
|
|
int var_queue_ RTC_GUARDED_BY(queue_);
|
2016-05-19 06:49:03 -07:00
|
|
|
};
|
|
|
|
|
|
2014-06-16 11:34:44 +00:00
|
|
|
// Just in case we ever get lumped together with other compilation units.
|
|
|
|
|
#undef ENABLE_THREAD_CHECKER
|
|
|
|
|
|
|
|
|
|
} // namespace rtc
|