Add tests and fix thread annotations

BUG=None
NOTRY=true

Review-Url: https://codereview.webrtc.org/2435293002
Cr-Commit-Position: refs/heads/master@{#14742}
This commit is contained in:
danilchap 2016-10-24 06:07:25 -07:00 committed by Commit bot
parent b60d1962d8
commit 01404084aa
3 changed files with 157 additions and 4 deletions

View File

@ -405,6 +405,7 @@ if (rtc_include_tests) {
"base/task_queue_unittest.cc",
"base/task_unittest.cc",
"base/testclient_unittest.cc",
"base/thread_annotations_unittest.cc",
"base/thread_checker_unittest.cc",
"base/thread_unittest.cc",
"base/timestampaligner_unittest.cc",

View File

@ -31,7 +31,7 @@
// indicates a shared variable should be guarded (by any lock). GUARDED_VAR
// is primarily used when the client cannot express the name of the lock.
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(guarded)
#define GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(guarded_var)
// Document if the memory location pointed to by a pointer should be guarded
// by a lock when dereferencing the pointer. Similar to GUARDED_VAR,
@ -41,8 +41,8 @@
// q, which is guarded by mu1, points to a shared memory location that is
// guarded by mu2, q should be annotated as follows:
// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded_by(x))
#define PT_GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded)
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
#define PT_GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_var)
// Document the acquisition order between locks that can be held
// simultaneously by a thread. For any two locks that need to be annotated
@ -65,7 +65,8 @@
// Document the locks acquired in the body of the function. These locks
// cannot be held when calling this function (as google3's Mutex locks are
// non-reentrant).
#define LOCKS_EXCLUDED(x) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(x))
#define LOCKS_EXCLUDED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
// Document the lock the annotated function returns without acquiring it.
#define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))

View File

@ -0,0 +1,151 @@
/*
* Copyright (c) 2016 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.
*/
#include "webrtc/base/thread_annotations.h"
#include "webrtc/test/gtest.h"
namespace {
class LOCKABLE Lock {
public:
void EnterWrite() const EXCLUSIVE_LOCK_FUNCTION() {}
void EnterRead() const SHARED_LOCK_FUNCTION() {}
bool TryEnterWrite() const EXCLUSIVE_TRYLOCK_FUNCTION(true) { return true; }
bool TryEnterRead() const SHARED_TRYLOCK_FUNCTION(true) { return true; }
void Leave() const UNLOCK_FUNCTION() {}
};
class SCOPED_LOCKABLE ScopeLock {
public:
explicit ScopeLock(const Lock& lock) EXCLUSIVE_LOCK_FUNCTION(lock) {}
~ScopeLock() UNLOCK_FUNCTION() {}
};
class ThreadSafe {
public:
ThreadSafe() {
pt_protected_by_lock_ = new int;
pt_protected_by_anything_ = new int;
}
~ThreadSafe() {
delete pt_protected_by_lock_;
delete pt_protected_by_anything_;
}
void LockInOrder() {
anylock_.EnterWrite();
lock_.EnterWrite();
pt_lock_.EnterWrite();
pt_lock_.Leave();
lock_.Leave();
anylock_.Leave();
}
void UnprotectedFunction() LOCKS_EXCLUDED(anylock_, lock_, pt_lock_) {
// Can access unprotected Value.
unprotected_ = 15;
// Can access pointers themself, but not data they point to.
int* tmp = pt_protected_by_lock_;
pt_protected_by_lock_ = pt_protected_by_anything_;
pt_protected_by_anything_ = tmp;
}
void ReadProtected() {
lock_.EnterRead();
unprotected_ = protected_by_anything_;
unprotected_ = protected_by_lock_;
lock_.Leave();
if (pt_lock_.TryEnterRead()) {
unprotected_ = *pt_protected_by_anything_;
unprotected_ = *pt_protected_by_lock_;
pt_lock_.Leave();
}
anylock_.EnterRead();
unprotected_ = protected_by_anything_;
unprotected_ = *pt_protected_by_anything_;
anylock_.Leave();
}
void WriteProtected() {
lock_.EnterWrite();
protected_by_anything_ = unprotected_;
protected_by_lock_ = unprotected_;
lock_.Leave();
if (pt_lock_.TryEnterWrite()) {
*pt_protected_by_anything_ = unprotected_;
*pt_protected_by_lock_ = unprotected_;
pt_lock_.Leave();
}
anylock_.EnterWrite();
protected_by_anything_ = unprotected_;
*pt_protected_by_anything_ = unprotected_;
anylock_.Leave();
}
void CallReadProtectedFunction() {
lock_.EnterRead();
pt_lock_.EnterRead();
ReadProtectedFunction();
pt_lock_.Leave();
lock_.Leave();
}
void CallWriteProtectedFunction() {
ScopeLock scope_lock(GetLock());
ScopeLock pt_scope_lock(pt_lock_);
WriteProtectedFunction();
}
private:
void ReadProtectedFunction() SHARED_LOCKS_REQUIRED(lock_, pt_lock_) {
unprotected_ = protected_by_lock_;
unprotected_ = *pt_protected_by_lock_;
}
void WriteProtectedFunction() EXCLUSIVE_LOCKS_REQUIRED(lock_, pt_lock_) {
int x = protected_by_lock_;
*pt_protected_by_lock_ = x;
protected_by_lock_ = unprotected_;
}
const Lock& GetLock() LOCK_RETURNED(lock_) { return lock_; }
Lock anylock_ ACQUIRED_BEFORE(lock_);
Lock lock_;
Lock pt_lock_ ACQUIRED_AFTER(lock_);
int unprotected_ = 0;
int protected_by_lock_ GUARDED_BY(lock_) = 0;
int protected_by_anything_ GUARDED_VAR = 0;
int* pt_protected_by_lock_ PT_GUARDED_BY(pt_lock_);
int* pt_protected_by_anything_ PT_GUARDED_VAR;
};
} // namespace
TEST(ThreadAnnotationsTest, Test) {
// This test ensure thread annotations doesn't break compilation.
// Thus no run-time expectations.
ThreadSafe t;
t.LockInOrder();
t.UnprotectedFunction();
t.ReadProtected();
t.WriteProtected();
t.CallReadProtectedFunction();
t.CallWriteProtectedFunction();
}