| /** @file |
| |
| Clang Thread Safety Analysis annotation macros. |
| |
| These wrap Clang's @c -Wthread-safety attributes so a lock's contract can be |
| expressed in the type system: which mutex guards which data, and which lock a |
| function requires its caller to hold. The compiler then proves, at build time, |
| that guarded data is only touched while the right lock is held. |
| |
| The annotations are compile-time only. Under Clang they expand to |
| @c __attribute__((...)) consumed by the analysis; under every other compiler |
| they expand to nothing. They generate no code and have zero runtime cost. |
| |
| Important note: Clang's analysis only tracks lock state through types marked as |
| capabilities (the mutex) and scoped capabilities (the RAII guard). The @c std:: |
| lock wrappers are deliberately flexible -- deferred locking, adopt/release, and |
| movability let the held state escape a single scope -- which makes it impossible |
| to track statically, and ATS does not need that flexibility. Annotated code |
| therefore takes its locks through ATS-owned annotated types -- @c ts::mutex with |
| @c ts::lock_guard, or @c ts::shared_mutex with @c ts::write_guard / |
| @c ts::read_guard -- whose simple acquire-in-constructor / |
| release-in-destructor contract the analysis can follow. |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you 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 |
| |
| #if defined(__clang__) |
| #define TS_THREAD_ANNOTATION(x) __attribute__((x)) |
| #else |
| #define TS_THREAD_ANNOTATION(x) |
| #endif |
| |
| /// Mark a class as a capability (a lock-like object that can be "held"). |
| #define TS_CAPABILITY(name) TS_THREAD_ANNOTATION(capability(name)) |
| |
| /// Mark an RAII type whose lifetime holds a capability (acquire in ctor, |
| /// release in dtor), e.g. a scoped lock guard. |
| #define TS_SCOPED_CAPABILITY TS_THREAD_ANNOTATION(scoped_lockable) |
| |
| /// The annotated data member may only be accessed while @a x is held. |
| #define TS_GUARDED_BY(x) TS_THREAD_ANNOTATION(guarded_by(x)) |
| |
| /// The data pointed to by the annotated pointer may only be accessed while |
| /// @a x is held. |
| #define TS_PT_GUARDED_BY(x) TS_THREAD_ANNOTATION(pt_guarded_by(x)) |
| |
| /// The function acquires the listed capabilities (exclusively / shared). |
| #define TS_ACQUIRE(...) TS_THREAD_ANNOTATION(acquire_capability(__VA_ARGS__)) |
| #define TS_ACQUIRE_SHARED(...) TS_THREAD_ANNOTATION(acquire_shared_capability(__VA_ARGS__)) |
| |
| /// The function releases the listed capabilities. Use the plain form (not the |
| /// shared form) on a scoped-capability destructor even for a shared guard. |
| #define TS_RELEASE(...) TS_THREAD_ANNOTATION(release_capability(__VA_ARGS__)) |
| #define TS_RELEASE_SHARED(...) TS_THREAD_ANNOTATION(release_shared_capability(__VA_ARGS__)) |
| |
| /// The function conditionally acquires a capability, holding it only on the |
| /// branch where it returns @a success_value. |
| #define TS_TRY_ACQUIRE(...) TS_THREAD_ANNOTATION(try_acquire_capability(__VA_ARGS__)) |
| #define TS_TRY_ACQUIRE_SHARED(...) TS_THREAD_ANNOTATION(try_acquire_shared_capability(__VA_ARGS__)) |
| |
| /// The caller must already hold the listed capabilities (exclusively / shared). |
| #define TS_REQUIRES(...) TS_THREAD_ANNOTATION(requires_capability(__VA_ARGS__)) |
| #define TS_REQUIRES_SHARED(...) TS_THREAD_ANNOTATION(requires_shared_capability(__VA_ARGS__)) |
| |
| /// The caller must NOT hold the listed capabilities (prevents self-deadlock). |
| #define TS_EXCLUDES(...) TS_THREAD_ANNOTATION(locks_excluded(__VA_ARGS__)) |
| |
| /// Declare that a getter returns a reference to the named capability. |
| #define TS_RETURN_CAPABILITY(x) TS_THREAD_ANNOTATION(lock_returned(x)) |
| |
| /// Tell the analysis a capability is held here without acquiring it (runtime |
| /// assertion form). |
| #define TS_ASSERT_CAPABILITY(x) TS_THREAD_ANNOTATION(assert_capability(x)) |
| #define TS_ASSERT_SHARED_CAPABILITY(x) TS_THREAD_ANNOTATION(assert_shared_capability(x)) |
| |
| /// Disable the analysis for a single function. Use sparingly, for code the |
| /// analysis cannot model (recursive acquire, hand-off across threads, |
| /// single-threaded destructors). |
| #define TS_NO_THREAD_SAFETY_ANALYSIS TS_THREAD_ANNOTATION(no_thread_safety_analysis) |