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