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