Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 982f7bd3 authored by Josh Gao's avatar Josh Gao
Browse files

base: add ScopedLockAssertion.

This is a useful helper for anyone that's using thread safety
annotations alongside std::condition_variable, extract it from adb and
move it to libbase.

Test: mma
Change-Id: Ic51e2f2a0e6a16628034b29d8ff32bf2155afccd
parent 5272f9b0
Loading
Loading
Loading
Loading
+5 −14
Original line number Original line Diff line number Diff line
@@ -52,6 +52,8 @@
#include "fdevent.h"
#include "fdevent.h"
#include "sysdeps/chrono.h"
#include "sysdeps/chrono.h"


using android::base::ScopedLockAssertion;

static void remove_transport(atransport* transport);
static void remove_transport(atransport* transport);
static void transport_unref(atransport* transport);
static void transport_unref(atransport* transport);


@@ -72,17 +74,6 @@ const char* const kFeatureAbb = "abb";


namespace {
namespace {


// A class that helps the Clang Thread Safety Analysis deal with
// std::unique_lock. Given that std::unique_lock is movable, and the analysis
// can not currently perform alias analysis, it is not annotated. In order to
// assert that the mutex is held, a ScopedAssumeLocked can be created just after
// the std::unique_lock.
class SCOPED_CAPABILITY ScopedAssumeLocked {
  public:
    ScopedAssumeLocked(std::mutex& mutex) ACQUIRE(mutex) {}
    ~ScopedAssumeLocked() RELEASE() {}
};

#if ADB_HOST
#if ADB_HOST
// Tracks and handles atransport*s that are attempting reconnection.
// Tracks and handles atransport*s that are attempting reconnection.
class ReconnectHandler {
class ReconnectHandler {
@@ -180,7 +171,7 @@ void ReconnectHandler::Run() {
        ReconnectAttempt attempt;
        ReconnectAttempt attempt;
        {
        {
            std::unique_lock<std::mutex> lock(reconnect_mutex_);
            std::unique_lock<std::mutex> lock(reconnect_mutex_);
            ScopedAssumeLocked assume_lock(reconnect_mutex_);
            ScopedLockAssertion assume_lock(reconnect_mutex_);


            if (!reconnect_queue_.empty()) {
            if (!reconnect_queue_.empty()) {
                // FIXME: libstdc++ (used on Windows) implements condition_variable with
                // FIXME: libstdc++ (used on Windows) implements condition_variable with
@@ -296,7 +287,7 @@ void BlockingConnectionAdapter::Start() {
        LOG(INFO) << this->transport_name_ << ": write thread spawning";
        LOG(INFO) << this->transport_name_ << ": write thread spawning";
        while (true) {
        while (true) {
            std::unique_lock<std::mutex> lock(mutex_);
            std::unique_lock<std::mutex> lock(mutex_);
            ScopedAssumeLocked assume_locked(mutex_);
            ScopedLockAssertion assume_locked(mutex_);
            cv_.wait(lock, [this]() REQUIRES(mutex_) {
            cv_.wait(lock, [this]() REQUIRES(mutex_) {
                return this->stopped_ || !this->write_queue_.empty();
                return this->stopped_ || !this->write_queue_.empty();
            });
            });
@@ -923,7 +914,7 @@ atransport* acquire_one_transport(TransportType type, const char* serial, Transp


bool ConnectionWaitable::WaitForConnection(std::chrono::milliseconds timeout) {
bool ConnectionWaitable::WaitForConnection(std::chrono::milliseconds timeout) {
    std::unique_lock<std::mutex> lock(mutex_);
    std::unique_lock<std::mutex> lock(mutex_);
    ScopedAssumeLocked assume_locked(mutex_);
    ScopedLockAssertion assume_locked(mutex_);
    return cv_.wait_for(lock, timeout, [&]() REQUIRES(mutex_) {
    return cv_.wait_for(lock, timeout, [&]() REQUIRES(mutex_) {
        return connection_established_ready_;
        return connection_established_ready_;
    }) && connection_established_;
    }) && connection_established_;
+38 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@


#pragma once
#pragma once


#include <mutex>

#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))


#define CAPABILITY(x) \
#define CAPABILITY(x) \
@@ -104,3 +106,39 @@


#define NO_THREAD_SAFETY_ANALYSIS \
#define NO_THREAD_SAFETY_ANALYSIS \
      THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
      THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)

namespace android {
namespace base {

// A class to help thread safety analysis deal with std::unique_lock and condition_variable.
//
// Clang's thread safety analysis currently doesn't perform alias analysis, so movable types
// like std::unique_lock can't be marked with thread safety annotations. This helper allows
// for manual assertion of lock state in a scope.
//
// For example:
//
//   std::mutex mutex;
//   std::condition_variable cv;
//   std::vector<int> vec GUARDED_BY(mutex);
//
//   int pop() {
//     std::unique_lock lock(mutex);
//     ScopedLockAssertion lock_assertion(mutex);
//     cv.wait(lock, []() {
//       ScopedLockAssertion lock_assertion(mutex);
//       return !vec.empty();
//     });
//
//     int result = vec.back();
//     vec.pop_back();
//     return result;
//   }
class SCOPED_CAPABILITY ScopedLockAssertion {
 public:
  ScopedLockAssertion(std::mutex& mutex) ACQUIRE(mutex) {}
  ~ScopedLockAssertion() RELEASE() {}
};

}  // namespace base
}  // namespace android