1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #define FTL_ATTRIBUTE(a) __attribute__((a))
20 
21 namespace android::ftl {
22 
23 // Granular alternative to [[clang::no_thread_safety_analysis]]. Given a std::mutex-like object,
24 // FakeGuard suppresses enforcement of thread-safe access to guarded variables within its scope.
25 // While FakeGuard is scoped to a block, there are macro shorthands for a single expression, as
26 // well as function/lambda scope (though calls must be indirect, e.g. virtual or std::function):
27 //
28 //   struct {
29 //     std::mutex mutex;
30 //     int x FTL_ATTRIBUTE(guarded_by(mutex)) = -1;
31 //
32 //     int f() {
33 //       {
34 //         ftl::FakeGuard guard(mutex);
35 //         x = 0;
36 //       }
37 //
38 //       return FTL_FAKE_GUARD(mutex, x + 1);
39 //     }
40 //
41 //      std::function<int()> g() const {
42 //        return [this]() FTL_FAKE_GUARD(mutex) { return x; };
43 //      }
44 //   } s;
45 //
46 //   assert(s.f() == 1);
47 //   assert(s.g()() == 0);
48 //
49 // An example of a situation where FakeGuard helps is a mutex that guards writes on Thread 1, and
50 // reads on Thread 2. Reads on Thread 1, which is the only writer, need not be under lock, so can
51 // use FakeGuard to appease the thread safety analyzer. Another example is enforcing and documenting
52 // exclusive access by a single thread. This is done by defining a global constant that represents a
53 // thread context, and annotating guarded variables as if it were a mutex (though without any effect
54 // at run time):
55 //
56 //   constexpr class [[clang::capability("mutex")]] {
57 //   } kMainThreadContext;
58 //
59 template <typename Mutex>
60 struct [[clang::scoped_lockable]] FakeGuard final {
FakeGuardfinal61   explicit FakeGuard(const Mutex& mutex) FTL_ATTRIBUTE(acquire_capability(mutex)) {}
~FakeGuardfinal62   [[clang::release_capability()]] ~FakeGuard() {}
63 
64   FakeGuard(const FakeGuard&) = delete;
65   FakeGuard& operator=(const FakeGuard&) = delete;
66 };
67 
68 }  // namespace android::ftl
69 
70 // TODO: Enable in C++23 once standard attributes can be used on lambdas.
71 #if 0
72 #define FTL_FAKE_GUARD1(mutex) [[using clang: acquire_capability(mutex), release_capability(mutex)]]
73 #else
74 #define FTL_FAKE_GUARD1(mutex)             \
75   FTL_ATTRIBUTE(acquire_capability(mutex)) \
76   FTL_ATTRIBUTE(release_capability(mutex))
77 #endif
78 
79 // The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
80 #define FTL_FAKE_GUARD2(mutex, expr)            \
81   [&]() -> decltype(auto) {                     \
82     const android::ftl::FakeGuard guard(mutex); \
83     return (expr);                              \
84   }()
85 
86 #define FTL_MAKE_FAKE_GUARD(arg1, arg2, guard, ...) guard
87 
88 #define FTL_FAKE_GUARD(...) \
89   FTL_MAKE_FAKE_GUARD(__VA_ARGS__, FTL_FAKE_GUARD2, FTL_FAKE_GUARD1, )(__VA_ARGS__)
90