1 | /* Copyright 2015 The TensorFlow Authors. All Rights Reserved. |
2 | |
3 | Licensed under the Apache License, Version 2.0 (the "License"); |
4 | you may not use this file except in compliance with the License. |
5 | You may obtain a copy of the License at |
6 | |
7 | http://www.apache.org/licenses/LICENSE-2.0 |
8 | |
9 | Unless required by applicable law or agreed to in writing, software |
10 | distributed under the License is distributed on an "AS IS" BASIS, |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | See the License for the specific language governing permissions and |
13 | limitations under the License. |
14 | ==============================================================================*/ |
15 | |
16 | // This header file contains the macro definitions for thread safety |
17 | // annotations that allow the developers to document the locking policies |
18 | // of their multi-threaded code. The annotations can also help program |
19 | // analysis tools to identify potential thread safety issues. |
20 | // |
21 | // The primary documentation on these annotations is external: |
22 | // http://clang.llvm.org/docs/ThreadSafetyAnalysis.html |
23 | // |
24 | // The annotations are implemented using compiler attributes. |
25 | // Using the macros defined here instead of the raw attributes allows |
26 | // for portability and future compatibility. |
27 | // |
28 | // When referring to mutexes in the arguments of the attributes, you should |
29 | // use variable names or more complex expressions (e.g. my_object->mutex_) |
30 | // that evaluate to a concrete mutex object whenever possible. If the mutex |
31 | // you want to refer to is not in scope, you may use a member pointer |
32 | // (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object. |
33 | // |
34 | |
35 | #ifndef TENSORFLOW_TSL_PLATFORM_THREAD_ANNOTATIONS_H_ |
36 | #define TENSORFLOW_TSL_PLATFORM_THREAD_ANNOTATIONS_H_ |
37 | |
38 | // IWYU pragma: private, include "third_party/tensorflow/tsl/platform/thread_annotations.h" |
39 | // IWYU pragma: friend third_party/tensorflow/tsl/platform/thread_annotations.h |
40 | |
41 | #if defined(__clang__) && (!defined(SWIG)) |
42 | #define TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x)) |
43 | #else |
44 | #define TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) // no-op |
45 | #endif |
46 | |
47 | // Document if a shared variable/field needs to be protected by a mutex. |
48 | // TF_GUARDED_BY allows the user to specify a particular mutex that should be |
49 | // held when accessing the annotated variable. GUARDED_VAR indicates that |
50 | // a shared variable is guarded by some unspecified mutex, for use in rare |
51 | // cases where a valid mutex expression cannot be specified. |
52 | #define TF_GUARDED_BY(x) TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x)) |
53 | #define GUARDED_VAR // no-op |
54 | |
55 | // Document if the memory location pointed to by a pointer should be guarded |
56 | // by a mutex when dereferencing the pointer. PT_GUARDED_VAR is analogous to |
57 | // GUARDED_VAR. Note that a pointer variable to a shared memory location |
58 | // could itself be a shared variable. For example, if a shared global pointer |
59 | // q, which is guarded by mu1, points to a shared memory location that is |
60 | // guarded by mu2, q should be annotated as follows: |
61 | // int *q TF_GUARDED_BY(mu1) TF_PT_GUARDED_BY(mu2); |
62 | #define TF_PT_GUARDED_BY(x) \ |
63 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x)) |
64 | #define TF_PT_GUARDED_VAR // no-op |
65 | |
66 | // Document the acquisition order between locks that can be held |
67 | // simultaneously by a thread. For any two locks that need to be annotated |
68 | // to establish an acquisition order, only one of them needs the annotation. |
69 | // (i.e. You don't have to annotate both locks with both TF_ACQUIRED_AFTER |
70 | // and TF_ACQUIRED_BEFORE.) |
71 | #define TF_ACQUIRED_AFTER(...) \ |
72 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__)) |
73 | |
74 | #define TF_ACQUIRED_BEFORE(...) \ |
75 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__)) |
76 | |
77 | #define TF_ACQUIRE(...) \ |
78 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquire_capability(__VA_ARGS__)) |
79 | |
80 | #define TF_ACQUIRE_SHARED(...) \ |
81 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \ |
82 | acquire_shared_capability(__VA_ARGS__)) |
83 | |
84 | #define TF_RELEASE(...) \ |
85 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(release_capability(__VA_ARGS__)) |
86 | |
87 | // Document a function that expects a mutex to be held prior to entry. |
88 | // The mutex is expected to be held both on entry to and exit from the |
89 | // function. |
90 | #define TF_EXCLUSIVE_LOCKS_REQUIRED(...) \ |
91 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(exclusive_locks_required(__VA_ARGS__)) |
92 | |
93 | #define TF_SHARED_LOCKS_REQUIRED(...) \ |
94 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_locks_required(__VA_ARGS__)) |
95 | |
96 | // Document the locks acquired in the body of the function. These locks |
97 | // cannot be held when calling this function (for instance, when the |
98 | // mutex implementation is non-reentrant). |
99 | #define TF_LOCKS_EXCLUDED(...) \ |
100 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__)) |
101 | |
102 | // Document a function that returns a mutex without acquiring it. For example, |
103 | // a public getter method that returns a pointer to a private mutex should |
104 | // be annotated with TF_LOCK_RETURNED. |
105 | #define TF_LOCK_RETURNED(x) \ |
106 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x)) |
107 | |
108 | // Document if a class/type is a lockable type (such as the Mutex class). |
109 | #define TF_LOCKABLE TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lockable) |
110 | |
111 | // Document if a class does RAII locking (such as the MutexLock class). |
112 | // The constructor should use LOCK_FUNCTION to specify the mutex that is |
113 | // acquired, and the destructor should use TF_UNLOCK_FUNCTION with no arguments; |
114 | // the analysis will assume that the destructor unlocks whatever the |
115 | // constructor locked. |
116 | #define TF_SCOPED_LOCKABLE \ |
117 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable) |
118 | |
119 | // Document functions that acquire a lock in the body of a function, and do |
120 | // not release it. |
121 | #define TF_EXCLUSIVE_LOCK_FUNCTION(...) \ |
122 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(exclusive_lock_function(__VA_ARGS__)) |
123 | |
124 | #define TF_SHARED_LOCK_FUNCTION(...) \ |
125 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_lock_function(__VA_ARGS__)) |
126 | |
127 | // Document functions that expect a lock to be held on entry to the function, |
128 | // and release it in the body of the function. |
129 | #define TF_UNLOCK_FUNCTION(...) \ |
130 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(unlock_function(__VA_ARGS__)) |
131 | |
132 | // Document functions that try to acquire a lock, and return success or failure |
133 | // (or a non-boolean value that can be interpreted as a boolean). |
134 | // The first argument should be true for functions that return true on success, |
135 | // or false for functions that return false on success. The second argument |
136 | // specifies the mutex that is locked on success. If unspecified, it is assumed |
137 | // to be 'this'. |
138 | #define TF_EXCLUSIVE_TRYLOCK_FUNCTION(...) \ |
139 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \ |
140 | exclusive_trylock_function(__VA_ARGS__)) |
141 | |
142 | #define TF_SHARED_TRYLOCK_FUNCTION(...) \ |
143 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_trylock_function(__VA_ARGS__)) |
144 | |
145 | // Document functions that dynamically check to see if a lock is held, and fail |
146 | // if it is not held. |
147 | #define TF_ASSERT_EXCLUSIVE_LOCK(...) \ |
148 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_exclusive_lock(__VA_ARGS__)) |
149 | |
150 | #define TF_ASSERT_SHARED_LOCK(...) \ |
151 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_lock(__VA_ARGS__)) |
152 | |
153 | // Turns off thread safety checking within the body of a particular function. |
154 | // This is used as an escape hatch for cases where either (a) the function |
155 | // is correct, but the locking is more complicated than the analyzer can handle, |
156 | // or (b) the function contains race conditions that are known to be benign. |
157 | #define TF_NO_THREAD_SAFETY_ANALYSIS \ |
158 | TF_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis) |
159 | |
160 | // TF_TS_UNCHECKED should be placed around lock expressions that are not valid |
161 | // C++ syntax, but which are present for documentation purposes. These |
162 | // annotations will be ignored by the analysis. |
163 | #define TF_TS_UNCHECKED(x) "" |
164 | |
165 | #endif // TENSORFLOW_TSL_PLATFORM_THREAD_ANNOTATIONS_H_ |
166 | |