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