File: fake_guard.h

package info (click to toggle)
android-platform-tools 34.0.5-12
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 150,900 kB
  • sloc: cpp: 805,786; java: 293,500; ansic: 128,288; xml: 127,491; python: 41,481; sh: 14,245; javascript: 9,665; cs: 3,846; asm: 2,049; makefile: 1,917; yacc: 440; awk: 368; ruby: 183; sql: 140; perl: 88; lex: 67
file content (90 lines) | stat: -rw-r--r-- 3,344 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#define FTL_ATTRIBUTE(a) __attribute__((a))

namespace android::ftl {

// Granular alternative to [[clang::no_thread_safety_analysis]]. Given a std::mutex-like object,
// FakeGuard suppresses enforcement of thread-safe access to guarded variables within its scope.
// While FakeGuard is scoped to a block, there are macro shorthands for a single expression, as
// well as function/lambda scope (though calls must be indirect, e.g. virtual or std::function):
//
//   struct {
//     std::mutex mutex;
//     int x FTL_ATTRIBUTE(guarded_by(mutex)) = -1;
//
//     int f() {
//       {
//         ftl::FakeGuard guard(mutex);
//         x = 0;
//       }
//
//       return FTL_FAKE_GUARD(mutex, x + 1);
//     }
//
//      std::function<int()> g() const {
//        return [this]() FTL_FAKE_GUARD(mutex) { return x; };
//      }
//   } s;
//
//   assert(s.f() == 1);
//   assert(s.g()() == 0);
//
// An example of a situation where FakeGuard helps is a mutex that guards writes on Thread 1, and
// reads on Thread 2. Reads on Thread 1, which is the only writer, need not be under lock, so can
// use FakeGuard to appease the thread safety analyzer. Another example is enforcing and documenting
// exclusive access by a single thread. This is done by defining a global constant that represents a
// thread context, and annotating guarded variables as if it were a mutex (though without any effect
// at run time):
//
//   constexpr class [[clang::capability("mutex")]] {
//   } kMainThreadContext;
//
template <typename Mutex>
struct [[clang::scoped_lockable]] FakeGuard final {
  explicit FakeGuard(const Mutex& mutex) FTL_ATTRIBUTE(acquire_capability(mutex)) {}
  [[clang::release_capability()]] ~FakeGuard() {}

  FakeGuard(const FakeGuard&) = delete;
  FakeGuard& operator=(const FakeGuard&) = delete;
};

}  // namespace android::ftl

// TODO: Enable in C++23 once standard attributes can be used on lambdas.
#if 0
#define FTL_FAKE_GUARD1(mutex) [[using clang: acquire_capability(mutex), release_capability(mutex)]]
#else
#define FTL_FAKE_GUARD1(mutex)             \
  FTL_ATTRIBUTE(acquire_capability(mutex)) \
  FTL_ATTRIBUTE(release_capability(mutex))
#endif

// The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
#define FTL_FAKE_GUARD2(mutex, expr)            \
  [&]() -> decltype(auto) {                     \
    const android::ftl::FakeGuard guard(mutex); \
    return (expr);                              \
  }()

#define FTL_MAKE_FAKE_GUARD(arg1, arg2, guard, ...) guard

// The void argument suppresses a warning about zero variadic macro arguments.
#define FTL_FAKE_GUARD(...) \
  FTL_MAKE_FAKE_GUARD(__VA_ARGS__, FTL_FAKE_GUARD2, FTL_FAKE_GUARD1, void)(__VA_ARGS__)