[fxl] make ThreadChecker BasicLockable

This CL makes ThreadChecker comply with BasicLockable so it can be
used in conjunction with static thread analysis. This allows e.g.
class members to be annotated with FXL_GUARDED_BY(thread_checker_)
to ensure that the thread is checked everywhere those members are
accessed.

TEST: added lock/unlock calls to existing unit test

Change-Id: I21264be75c8ed64ca71d40eb18d752021cad20b1
diff --git a/public/lib/fxl/synchronization/thread_annotations.h b/public/lib/fxl/synchronization/thread_annotations.h
index e818d4f..d9f2bec 100644
--- a/public/lib/fxl/synchronization/thread_annotations.h
+++ b/public/lib/fxl/synchronization/thread_annotations.h
@@ -23,6 +23,8 @@
 #define FXL_THREAD_ANNOTATION_ATTRIBUTE__(x)
 #endif
 
+#define FXL_CAPABILITY(x) FXL_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
 #define FXL_GUARDED_BY(x) FXL_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
 
 #define FXL_PT_GUARDED_BY(x) FXL_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
diff --git a/public/lib/fxl/synchronization/thread_checker.h b/public/lib/fxl/synchronization/thread_checker.h
index b36e3d5..e1a800a 100644
--- a/public/lib/fxl/synchronization/thread_checker.h
+++ b/public/lib/fxl/synchronization/thread_checker.h
@@ -14,6 +14,7 @@
 
 #include "lib/fxl/logging.h"
 #include "lib/fxl/macros.h"
+#include "lib/fxl/synchronization/thread_annotations.h"
 
 namespace fxl {
 
@@ -25,7 +26,27 @@
 // #ifdef it out if you want something Debug-only). (Rationale: Having a
 // |CalledOnValidThread()| that lies in Release builds seems bad. Moreover,
 // there's a small space cost to having even an empty class. )
-class ThreadChecker final {
+//
+// In addition to providing an explicity check of the current thread,
+// |ThreadChecker| commplies with BasicLockable, checking the current thread
+// when |lock| is called. This allows static thread safety analysis to be used
+// to ensure that resources are accessed in a context that is checked (at debug
+// runtime) to ensure that it's running on the correct thread:
+//
+// class MyClass {
+//  public:
+//    void Foo() {
+//      std::lock_guard<fxl::ThreadChecker> locker(thread_checker_);
+//      resource_ = 0;
+//    }
+//  private:
+//   mutable fxl::ThreadChecker thread_checker_;
+//   int resource_ FXL_GUARDED_BY(thread_checker_);
+// }
+//
+// Note: |lock| checks the thread in debug builds only.
+//
+class FXL_CAPABILITY("mutex") ThreadChecker final {
  public:
   ThreadChecker() : self_(pthread_self()) {}
   ~ThreadChecker() {}
@@ -36,6 +57,12 @@
     return !!pthread_equal(pthread_self(), self_);
   }
 
+  void lock() FXL_ACQUIRE() {
+    FXL_DCHECK(IsCreationThreadCurrent());
+  }
+
+  void unlock() FXL_RELEASE() {}
+
  private:
   const pthread_t self_;
 
diff --git a/public/lib/fxl/synchronization/thread_checker_unittest.cc b/public/lib/fxl/synchronization/thread_checker_unittest.cc
index f95b493..ab39ba6 100644
--- a/public/lib/fxl/synchronization/thread_checker_unittest.cc
+++ b/public/lib/fxl/synchronization/thread_checker_unittest.cc
@@ -21,11 +21,15 @@
 TEST(ThreadCheckerTest, DifferentThreads) {
   ThreadChecker checker1;
   EXPECT_TRUE(checker1.IsCreationThreadCurrent());
+  checker1.lock();
+  checker1.unlock();
 
   std::thread thread([&checker1]() {
     ThreadChecker checker2;
     EXPECT_TRUE(checker2.IsCreationThreadCurrent());
     EXPECT_FALSE(checker1.IsCreationThreadCurrent());
+    checker2.lock();
+    checker2.unlock();
   });
   thread.join();