Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
michael@0 | 1 | /* Copyright (c) 2011, Google Inc. |
michael@0 | 2 | * All rights reserved. |
michael@0 | 3 | * |
michael@0 | 4 | * Redistribution and use in source and binary forms, with or without |
michael@0 | 5 | * modification, are permitted provided that the following conditions are |
michael@0 | 6 | * met: |
michael@0 | 7 | * |
michael@0 | 8 | * * Redistributions of source code must retain the above copyright |
michael@0 | 9 | * notice, this list of conditions and the following disclaimer. |
michael@0 | 10 | * * Neither the name of Google Inc. nor the names of its |
michael@0 | 11 | * contributors may be used to endorse or promote products derived from |
michael@0 | 12 | * this software without specific prior written permission. |
michael@0 | 13 | * |
michael@0 | 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 15 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 16 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 17 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 18 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 20 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 25 | */ |
michael@0 | 26 | |
michael@0 | 27 | /* This file defines dynamic annotations for use with dynamic analysis |
michael@0 | 28 | tool such as valgrind, PIN, etc. |
michael@0 | 29 | |
michael@0 | 30 | Dynamic annotation is a source code annotation that affects |
michael@0 | 31 | the generated code (that is, the annotation is not a comment). |
michael@0 | 32 | Each such annotation is attached to a particular |
michael@0 | 33 | instruction and/or to a particular object (address) in the program. |
michael@0 | 34 | |
michael@0 | 35 | The annotations that should be used by users are macros in all upper-case |
michael@0 | 36 | (e.g., ANNOTATE_NEW_MEMORY). |
michael@0 | 37 | |
michael@0 | 38 | Actual implementation of these macros may differ depending on the |
michael@0 | 39 | dynamic analysis tool being used. |
michael@0 | 40 | |
michael@0 | 41 | See http://code.google.com/p/data-race-test/ for more information. |
michael@0 | 42 | |
michael@0 | 43 | This file supports the following dynamic analysis tools: |
michael@0 | 44 | - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero). |
michael@0 | 45 | Macros are defined empty. |
michael@0 | 46 | - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1). |
michael@0 | 47 | Macros are defined as calls to non-inlinable empty functions |
michael@0 | 48 | that are intercepted by Valgrind. */ |
michael@0 | 49 | |
michael@0 | 50 | #ifndef __DYNAMIC_ANNOTATIONS_H__ |
michael@0 | 51 | #define __DYNAMIC_ANNOTATIONS_H__ |
michael@0 | 52 | |
michael@0 | 53 | #ifndef DYNAMIC_ANNOTATIONS_PREFIX |
michael@0 | 54 | # define DYNAMIC_ANNOTATIONS_PREFIX |
michael@0 | 55 | #endif |
michael@0 | 56 | |
michael@0 | 57 | #ifndef DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND |
michael@0 | 58 | # define DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND 1 |
michael@0 | 59 | #endif |
michael@0 | 60 | |
michael@0 | 61 | #ifdef DYNAMIC_ANNOTATIONS_WANT_ATTRIBUTE_WEAK |
michael@0 | 62 | # ifdef __GNUC__ |
michael@0 | 63 | # define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK __attribute__((weak)) |
michael@0 | 64 | # else |
michael@0 | 65 | /* TODO(glider): for Windows support we may want to change this macro in order |
michael@0 | 66 | to prepend __declspec(selectany) to the annotations' declarations. */ |
michael@0 | 67 | # error weak annotations are not supported for your compiler |
michael@0 | 68 | # endif |
michael@0 | 69 | #else |
michael@0 | 70 | # define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK |
michael@0 | 71 | #endif |
michael@0 | 72 | |
michael@0 | 73 | /* The following preprocessor magic prepends the value of |
michael@0 | 74 | DYNAMIC_ANNOTATIONS_PREFIX to annotation function names. */ |
michael@0 | 75 | #define DYNAMIC_ANNOTATIONS_GLUE0(A, B) A##B |
michael@0 | 76 | #define DYNAMIC_ANNOTATIONS_GLUE(A, B) DYNAMIC_ANNOTATIONS_GLUE0(A, B) |
michael@0 | 77 | #define DYNAMIC_ANNOTATIONS_NAME(name) \ |
michael@0 | 78 | DYNAMIC_ANNOTATIONS_GLUE(DYNAMIC_ANNOTATIONS_PREFIX, name) |
michael@0 | 79 | |
michael@0 | 80 | #ifndef DYNAMIC_ANNOTATIONS_ENABLED |
michael@0 | 81 | # define DYNAMIC_ANNOTATIONS_ENABLED 0 |
michael@0 | 82 | #endif |
michael@0 | 83 | |
michael@0 | 84 | #if DYNAMIC_ANNOTATIONS_ENABLED != 0 |
michael@0 | 85 | |
michael@0 | 86 | /* ------------------------------------------------------------- |
michael@0 | 87 | Annotations useful when implementing condition variables such as CondVar, |
michael@0 | 88 | using conditional critical sections (Await/LockWhen) and when constructing |
michael@0 | 89 | user-defined synchronization mechanisms. |
michael@0 | 90 | |
michael@0 | 91 | The annotations ANNOTATE_HAPPENS_BEFORE() and ANNOTATE_HAPPENS_AFTER() can |
michael@0 | 92 | be used to define happens-before arcs in user-defined synchronization |
michael@0 | 93 | mechanisms: the race detector will infer an arc from the former to the |
michael@0 | 94 | latter when they share the same argument pointer. |
michael@0 | 95 | |
michael@0 | 96 | Example 1 (reference counting): |
michael@0 | 97 | |
michael@0 | 98 | void Unref() { |
michael@0 | 99 | ANNOTATE_HAPPENS_BEFORE(&refcount_); |
michael@0 | 100 | if (AtomicDecrementByOne(&refcount_) == 0) { |
michael@0 | 101 | ANNOTATE_HAPPENS_AFTER(&refcount_); |
michael@0 | 102 | delete this; |
michael@0 | 103 | } |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | Example 2 (message queue): |
michael@0 | 107 | |
michael@0 | 108 | void MyQueue::Put(Type *e) { |
michael@0 | 109 | MutexLock lock(&mu_); |
michael@0 | 110 | ANNOTATE_HAPPENS_BEFORE(e); |
michael@0 | 111 | PutElementIntoMyQueue(e); |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | Type *MyQueue::Get() { |
michael@0 | 115 | MutexLock lock(&mu_); |
michael@0 | 116 | Type *e = GetElementFromMyQueue(); |
michael@0 | 117 | ANNOTATE_HAPPENS_AFTER(e); |
michael@0 | 118 | return e; |
michael@0 | 119 | } |
michael@0 | 120 | |
michael@0 | 121 | Note: when possible, please use the existing reference counting and message |
michael@0 | 122 | queue implementations instead of inventing new ones. */ |
michael@0 | 123 | |
michael@0 | 124 | /* Report that wait on the condition variable at address "cv" has succeeded |
michael@0 | 125 | and the lock at address "lock" is held. */ |
michael@0 | 126 | #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \ |
michael@0 | 127 | DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, lock) |
michael@0 | 128 | |
michael@0 | 129 | /* Report that wait on the condition variable at "cv" has succeeded. Variant |
michael@0 | 130 | w/o lock. */ |
michael@0 | 131 | #define ANNOTATE_CONDVAR_WAIT(cv) \ |
michael@0 | 132 | DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, NULL) |
michael@0 | 133 | |
michael@0 | 134 | /* Report that we are about to signal on the condition variable at address |
michael@0 | 135 | "cv". */ |
michael@0 | 136 | #define ANNOTATE_CONDVAR_SIGNAL(cv) \ |
michael@0 | 137 | DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(__FILE__, __LINE__, cv) |
michael@0 | 138 | |
michael@0 | 139 | /* Report that we are about to signal_all on the condition variable at address |
michael@0 | 140 | "cv". */ |
michael@0 | 141 | #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \ |
michael@0 | 142 | DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(__FILE__, __LINE__, cv) |
michael@0 | 143 | |
michael@0 | 144 | /* Annotations for user-defined synchronization mechanisms. */ |
michael@0 | 145 | #define ANNOTATE_HAPPENS_BEFORE(obj) \ |
michael@0 | 146 | DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(__FILE__, __LINE__, obj) |
michael@0 | 147 | #define ANNOTATE_HAPPENS_AFTER(obj) \ |
michael@0 | 148 | DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(__FILE__, __LINE__, obj) |
michael@0 | 149 | |
michael@0 | 150 | /* DEPRECATED. Don't use it. */ |
michael@0 | 151 | #define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \ |
michael@0 | 152 | DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(__FILE__, __LINE__, \ |
michael@0 | 153 | pointer, size) |
michael@0 | 154 | |
michael@0 | 155 | /* DEPRECATED. Don't use it. */ |
michael@0 | 156 | #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) \ |
michael@0 | 157 | DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(__FILE__, __LINE__, \ |
michael@0 | 158 | pointer, size) |
michael@0 | 159 | |
michael@0 | 160 | /* DEPRECATED. Don't use it. */ |
michael@0 | 161 | #define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size) \ |
michael@0 | 162 | do { \ |
michael@0 | 163 | ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size); \ |
michael@0 | 164 | ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size); \ |
michael@0 | 165 | } while (0) |
michael@0 | 166 | |
michael@0 | 167 | /* Instruct the tool to create a happens-before arc between mu->Unlock() and |
michael@0 | 168 | mu->Lock(). This annotation may slow down the race detector and hide real |
michael@0 | 169 | races. Normally it is used only when it would be difficult to annotate each |
michael@0 | 170 | of the mutex's critical sections individually using the annotations above. |
michael@0 | 171 | This annotation makes sense only for hybrid race detectors. For pure |
michael@0 | 172 | happens-before detectors this is a no-op. For more details see |
michael@0 | 173 | http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */ |
michael@0 | 174 | #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \ |
michael@0 | 175 | DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \ |
michael@0 | 176 | mu) |
michael@0 | 177 | |
michael@0 | 178 | /* Opposite to ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. |
michael@0 | 179 | Instruct the tool to NOT create h-b arcs between Unlock and Lock, even in |
michael@0 | 180 | pure happens-before mode. For a hybrid mode this is a no-op. */ |
michael@0 | 181 | #define ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX(mu) \ |
michael@0 | 182 | DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(__FILE__, __LINE__, mu) |
michael@0 | 183 | |
michael@0 | 184 | /* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */ |
michael@0 | 185 | #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \ |
michael@0 | 186 | DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \ |
michael@0 | 187 | mu) |
michael@0 | 188 | |
michael@0 | 189 | /* ------------------------------------------------------------- |
michael@0 | 190 | Annotations useful when defining memory allocators, or when memory that |
michael@0 | 191 | was protected in one way starts to be protected in another. */ |
michael@0 | 192 | |
michael@0 | 193 | /* Report that a new memory at "address" of size "size" has been allocated. |
michael@0 | 194 | This might be used when the memory has been retrieved from a free list and |
michael@0 | 195 | is about to be reused, or when a the locking discipline for a variable |
michael@0 | 196 | changes. */ |
michael@0 | 197 | #define ANNOTATE_NEW_MEMORY(address, size) \ |
michael@0 | 198 | DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(__FILE__, __LINE__, address, \ |
michael@0 | 199 | size) |
michael@0 | 200 | |
michael@0 | 201 | /* ------------------------------------------------------------- |
michael@0 | 202 | Annotations useful when defining FIFO queues that transfer data between |
michael@0 | 203 | threads. */ |
michael@0 | 204 | |
michael@0 | 205 | /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at |
michael@0 | 206 | address "pcq" has been created. The ANNOTATE_PCQ_* annotations |
michael@0 | 207 | should be used only for FIFO queues. For non-FIFO queues use |
michael@0 | 208 | ANNOTATE_HAPPENS_BEFORE (for put) and ANNOTATE_HAPPENS_AFTER (for get). */ |
michael@0 | 209 | #define ANNOTATE_PCQ_CREATE(pcq) \ |
michael@0 | 210 | DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(__FILE__, __LINE__, pcq) |
michael@0 | 211 | |
michael@0 | 212 | /* Report that the queue at address "pcq" is about to be destroyed. */ |
michael@0 | 213 | #define ANNOTATE_PCQ_DESTROY(pcq) \ |
michael@0 | 214 | DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(__FILE__, __LINE__, pcq) |
michael@0 | 215 | |
michael@0 | 216 | /* Report that we are about to put an element into a FIFO queue at address |
michael@0 | 217 | "pcq". */ |
michael@0 | 218 | #define ANNOTATE_PCQ_PUT(pcq) \ |
michael@0 | 219 | DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(__FILE__, __LINE__, pcq) |
michael@0 | 220 | |
michael@0 | 221 | /* Report that we've just got an element from a FIFO queue at address |
michael@0 | 222 | "pcq". */ |
michael@0 | 223 | #define ANNOTATE_PCQ_GET(pcq) \ |
michael@0 | 224 | DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(__FILE__, __LINE__, pcq) |
michael@0 | 225 | |
michael@0 | 226 | /* ------------------------------------------------------------- |
michael@0 | 227 | Annotations that suppress errors. It is usually better to express the |
michael@0 | 228 | program's synchronization using the other annotations, but these can |
michael@0 | 229 | be used when all else fails. */ |
michael@0 | 230 | |
michael@0 | 231 | /* Report that we may have a benign race at "pointer", with size |
michael@0 | 232 | "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the |
michael@0 | 233 | point where "pointer" has been allocated, preferably close to the point |
michael@0 | 234 | where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. */ |
michael@0 | 235 | #define ANNOTATE_BENIGN_RACE(pointer, description) \ |
michael@0 | 236 | DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \ |
michael@0 | 237 | pointer, sizeof(*(pointer)), description) |
michael@0 | 238 | |
michael@0 | 239 | /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to |
michael@0 | 240 | the memory range [address, address+size). */ |
michael@0 | 241 | #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ |
michael@0 | 242 | DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \ |
michael@0 | 243 | address, size, description) |
michael@0 | 244 | |
michael@0 | 245 | /* Request the analysis tool to ignore all reads in the current thread |
michael@0 | 246 | until ANNOTATE_IGNORE_READS_END is called. |
michael@0 | 247 | Useful to ignore intentional racey reads, while still checking |
michael@0 | 248 | other reads and all writes. |
michael@0 | 249 | See also ANNOTATE_UNPROTECTED_READ. */ |
michael@0 | 250 | #define ANNOTATE_IGNORE_READS_BEGIN() \ |
michael@0 | 251 | DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__) |
michael@0 | 252 | |
michael@0 | 253 | /* Stop ignoring reads. */ |
michael@0 | 254 | #define ANNOTATE_IGNORE_READS_END() \ |
michael@0 | 255 | DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__) |
michael@0 | 256 | |
michael@0 | 257 | /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */ |
michael@0 | 258 | #define ANNOTATE_IGNORE_WRITES_BEGIN() \ |
michael@0 | 259 | DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__) |
michael@0 | 260 | |
michael@0 | 261 | /* Stop ignoring writes. */ |
michael@0 | 262 | #define ANNOTATE_IGNORE_WRITES_END() \ |
michael@0 | 263 | DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__) |
michael@0 | 264 | |
michael@0 | 265 | /* Start ignoring all memory accesses (reads and writes). */ |
michael@0 | 266 | #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ |
michael@0 | 267 | do {\ |
michael@0 | 268 | ANNOTATE_IGNORE_READS_BEGIN();\ |
michael@0 | 269 | ANNOTATE_IGNORE_WRITES_BEGIN();\ |
michael@0 | 270 | }while(0)\ |
michael@0 | 271 | |
michael@0 | 272 | /* Stop ignoring all memory accesses. */ |
michael@0 | 273 | #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \ |
michael@0 | 274 | do {\ |
michael@0 | 275 | ANNOTATE_IGNORE_WRITES_END();\ |
michael@0 | 276 | ANNOTATE_IGNORE_READS_END();\ |
michael@0 | 277 | }while(0)\ |
michael@0 | 278 | |
michael@0 | 279 | /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events: |
michael@0 | 280 | RWLOCK* and CONDVAR*. */ |
michael@0 | 281 | #define ANNOTATE_IGNORE_SYNC_BEGIN() \ |
michael@0 | 282 | DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(__FILE__, __LINE__) |
michael@0 | 283 | |
michael@0 | 284 | /* Stop ignoring sync events. */ |
michael@0 | 285 | #define ANNOTATE_IGNORE_SYNC_END() \ |
michael@0 | 286 | DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(__FILE__, __LINE__) |
michael@0 | 287 | |
michael@0 | 288 | |
michael@0 | 289 | /* Enable (enable!=0) or disable (enable==0) race detection for all threads. |
michael@0 | 290 | This annotation could be useful if you want to skip expensive race analysis |
michael@0 | 291 | during some period of program execution, e.g. during initialization. */ |
michael@0 | 292 | #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \ |
michael@0 | 293 | DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(__FILE__, __LINE__, \ |
michael@0 | 294 | enable) |
michael@0 | 295 | |
michael@0 | 296 | /* ------------------------------------------------------------- |
michael@0 | 297 | Annotations useful for debugging. */ |
michael@0 | 298 | |
michael@0 | 299 | /* Request to trace every access to "address". */ |
michael@0 | 300 | #define ANNOTATE_TRACE_MEMORY(address) \ |
michael@0 | 301 | DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(__FILE__, __LINE__, address) |
michael@0 | 302 | |
michael@0 | 303 | /* Report the current thread name to a race detector. */ |
michael@0 | 304 | #define ANNOTATE_THREAD_NAME(name) \ |
michael@0 | 305 | DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(__FILE__, __LINE__, name) |
michael@0 | 306 | |
michael@0 | 307 | /* ------------------------------------------------------------- |
michael@0 | 308 | Annotations useful when implementing locks. They are not |
michael@0 | 309 | normally needed by modules that merely use locks. |
michael@0 | 310 | The "lock" argument is a pointer to the lock object. */ |
michael@0 | 311 | |
michael@0 | 312 | /* Report that a lock has been created at address "lock". */ |
michael@0 | 313 | #define ANNOTATE_RWLOCK_CREATE(lock) \ |
michael@0 | 314 | DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(__FILE__, __LINE__, lock) |
michael@0 | 315 | |
michael@0 | 316 | /* Report that the lock at address "lock" is about to be destroyed. */ |
michael@0 | 317 | #define ANNOTATE_RWLOCK_DESTROY(lock) \ |
michael@0 | 318 | DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock) |
michael@0 | 319 | |
michael@0 | 320 | /* Report that the lock at address "lock" has been acquired. |
michael@0 | 321 | is_w=1 for writer lock, is_w=0 for reader lock. */ |
michael@0 | 322 | #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ |
michael@0 | 323 | DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(__FILE__, __LINE__, lock, \ |
michael@0 | 324 | is_w) |
michael@0 | 325 | |
michael@0 | 326 | /* Report that the lock at address "lock" is about to be released. */ |
michael@0 | 327 | #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ |
michael@0 | 328 | DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(__FILE__, __LINE__, lock, \ |
michael@0 | 329 | is_w) |
michael@0 | 330 | |
michael@0 | 331 | /* ------------------------------------------------------------- |
michael@0 | 332 | Annotations useful when implementing barriers. They are not |
michael@0 | 333 | normally needed by modules that merely use barriers. |
michael@0 | 334 | The "barrier" argument is a pointer to the barrier object. */ |
michael@0 | 335 | |
michael@0 | 336 | /* Report that the "barrier" has been initialized with initial "count". |
michael@0 | 337 | If 'reinitialization_allowed' is true, initialization is allowed to happen |
michael@0 | 338 | multiple times w/o calling barrier_destroy() */ |
michael@0 | 339 | #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \ |
michael@0 | 340 | DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(__FILE__, __LINE__, barrier, \ |
michael@0 | 341 | count, reinitialization_allowed) |
michael@0 | 342 | |
michael@0 | 343 | /* Report that we are about to enter barrier_wait("barrier"). */ |
michael@0 | 344 | #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \ |
michael@0 | 345 | DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(__FILE__, __LINE__, \ |
michael@0 | 346 | barrier) |
michael@0 | 347 | |
michael@0 | 348 | /* Report that we just exited barrier_wait("barrier"). */ |
michael@0 | 349 | #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \ |
michael@0 | 350 | DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(__FILE__, __LINE__, \ |
michael@0 | 351 | barrier) |
michael@0 | 352 | |
michael@0 | 353 | /* Report that the "barrier" has been destroyed. */ |
michael@0 | 354 | #define ANNOTATE_BARRIER_DESTROY(barrier) \ |
michael@0 | 355 | DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(__FILE__, __LINE__, \ |
michael@0 | 356 | barrier) |
michael@0 | 357 | |
michael@0 | 358 | /* ------------------------------------------------------------- |
michael@0 | 359 | Annotations useful for testing race detectors. */ |
michael@0 | 360 | |
michael@0 | 361 | /* Report that we expect a race on the variable at "address". |
michael@0 | 362 | Use only in unit tests for a race detector. */ |
michael@0 | 363 | #define ANNOTATE_EXPECT_RACE(address, description) \ |
michael@0 | 364 | DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(__FILE__, __LINE__, address, \ |
michael@0 | 365 | description) |
michael@0 | 366 | |
michael@0 | 367 | #define ANNOTATE_FLUSH_EXPECTED_RACES() \ |
michael@0 | 368 | DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(__FILE__, __LINE__) |
michael@0 | 369 | |
michael@0 | 370 | /* A no-op. Insert where you like to test the interceptors. */ |
michael@0 | 371 | #define ANNOTATE_NO_OP(arg) \ |
michael@0 | 372 | DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(__FILE__, __LINE__, arg) |
michael@0 | 373 | |
michael@0 | 374 | /* Force the race detector to flush its state. The actual effect depends on |
michael@0 | 375 | * the implementation of the detector. */ |
michael@0 | 376 | #define ANNOTATE_FLUSH_STATE() \ |
michael@0 | 377 | DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(__FILE__, __LINE__) |
michael@0 | 378 | |
michael@0 | 379 | |
michael@0 | 380 | #else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ |
michael@0 | 381 | |
michael@0 | 382 | #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */ |
michael@0 | 383 | #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */ |
michael@0 | 384 | #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */ |
michael@0 | 385 | #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */ |
michael@0 | 386 | #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */ |
michael@0 | 387 | #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */ |
michael@0 | 388 | #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */ |
michael@0 | 389 | #define ANNOTATE_BARRIER_DESTROY(barrier) /* empty */ |
michael@0 | 390 | #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */ |
michael@0 | 391 | #define ANNOTATE_CONDVAR_WAIT(cv) /* empty */ |
michael@0 | 392 | #define ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */ |
michael@0 | 393 | #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */ |
michael@0 | 394 | #define ANNOTATE_HAPPENS_BEFORE(obj) /* empty */ |
michael@0 | 395 | #define ANNOTATE_HAPPENS_AFTER(obj) /* empty */ |
michael@0 | 396 | #define ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */ |
michael@0 | 397 | #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size) /* empty */ |
michael@0 | 398 | #define ANNOTATE_SWAP_MEMORY_RANGE(address, size) /* empty */ |
michael@0 | 399 | #define ANNOTATE_PCQ_CREATE(pcq) /* empty */ |
michael@0 | 400 | #define ANNOTATE_PCQ_DESTROY(pcq) /* empty */ |
michael@0 | 401 | #define ANNOTATE_PCQ_PUT(pcq) /* empty */ |
michael@0 | 402 | #define ANNOTATE_PCQ_GET(pcq) /* empty */ |
michael@0 | 403 | #define ANNOTATE_NEW_MEMORY(address, size) /* empty */ |
michael@0 | 404 | #define ANNOTATE_EXPECT_RACE(address, description) /* empty */ |
michael@0 | 405 | #define ANNOTATE_FLUSH_EXPECTED_RACES(address, description) /* empty */ |
michael@0 | 406 | #define ANNOTATE_BENIGN_RACE(address, description) /* empty */ |
michael@0 | 407 | #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */ |
michael@0 | 408 | #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */ |
michael@0 | 409 | #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */ |
michael@0 | 410 | #define ANNOTATE_TRACE_MEMORY(arg) /* empty */ |
michael@0 | 411 | #define ANNOTATE_THREAD_NAME(name) /* empty */ |
michael@0 | 412 | #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */ |
michael@0 | 413 | #define ANNOTATE_IGNORE_READS_END() /* empty */ |
michael@0 | 414 | #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */ |
michael@0 | 415 | #define ANNOTATE_IGNORE_WRITES_END() /* empty */ |
michael@0 | 416 | #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */ |
michael@0 | 417 | #define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */ |
michael@0 | 418 | #define ANNOTATE_IGNORE_SYNC_BEGIN() /* empty */ |
michael@0 | 419 | #define ANNOTATE_IGNORE_SYNC_END() /* empty */ |
michael@0 | 420 | #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */ |
michael@0 | 421 | #define ANNOTATE_NO_OP(arg) /* empty */ |
michael@0 | 422 | #define ANNOTATE_FLUSH_STATE() /* empty */ |
michael@0 | 423 | |
michael@0 | 424 | #endif /* DYNAMIC_ANNOTATIONS_ENABLED */ |
michael@0 | 425 | |
michael@0 | 426 | /* Use the macros above rather than using these functions directly. */ |
michael@0 | 427 | #ifdef __cplusplus |
michael@0 | 428 | extern "C" { |
michael@0 | 429 | #endif |
michael@0 | 430 | |
michael@0 | 431 | |
michael@0 | 432 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)( |
michael@0 | 433 | const char *file, int line, |
michael@0 | 434 | const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 435 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)( |
michael@0 | 436 | const char *file, int line, |
michael@0 | 437 | const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 438 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)( |
michael@0 | 439 | const char *file, int line, |
michael@0 | 440 | const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 441 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)( |
michael@0 | 442 | const char *file, int line, |
michael@0 | 443 | const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 444 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)( |
michael@0 | 445 | const char *file, int line, const volatile void *barrier, long count, |
michael@0 | 446 | long reinitialization_allowed) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 447 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)( |
michael@0 | 448 | const char *file, int line, |
michael@0 | 449 | const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 450 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)( |
michael@0 | 451 | const char *file, int line, |
michael@0 | 452 | const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 453 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)( |
michael@0 | 454 | const char *file, int line, |
michael@0 | 455 | const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 456 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)( |
michael@0 | 457 | const char *file, int line, const volatile void *cv, |
michael@0 | 458 | const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 459 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)( |
michael@0 | 460 | const char *file, int line, |
michael@0 | 461 | const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 462 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)( |
michael@0 | 463 | const char *file, int line, |
michael@0 | 464 | const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 465 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)( |
michael@0 | 466 | const char *file, int line, |
michael@0 | 467 | const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 468 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)( |
michael@0 | 469 | const char *file, int line, |
michael@0 | 470 | const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 471 | void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)( |
michael@0 | 472 | const char *file, int line, |
michael@0 | 473 | const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 474 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)( |
michael@0 | 475 | const char *file, int line, |
michael@0 | 476 | const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 477 | void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)( |
michael@0 | 478 | const char *file, int line, |
michael@0 | 479 | const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 480 | void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)( |
michael@0 | 481 | const char *file, int line, |
michael@0 | 482 | const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 483 | void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)( |
michael@0 | 484 | const char *file, int line, |
michael@0 | 485 | const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 486 | void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)( |
michael@0 | 487 | const char *file, int line, |
michael@0 | 488 | const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 489 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)( |
michael@0 | 490 | const char *file, int line, |
michael@0 | 491 | const volatile void *mem, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 492 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)( |
michael@0 | 493 | const char *file, int line, const volatile void *mem, |
michael@0 | 494 | const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 495 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)( |
michael@0 | 496 | const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 497 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)( |
michael@0 | 498 | const char *file, int line, const volatile void *mem, |
michael@0 | 499 | const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 500 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)( |
michael@0 | 501 | const char *file, int line, const volatile void *mem, long size, |
michael@0 | 502 | const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 503 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)( |
michael@0 | 504 | const char *file, int line, |
michael@0 | 505 | const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 506 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)( |
michael@0 | 507 | const char *file, int line, |
michael@0 | 508 | const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 509 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)( |
michael@0 | 510 | const char *file, int line, |
michael@0 | 511 | const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 512 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)( |
michael@0 | 513 | const char *file, int line, |
michael@0 | 514 | const char *name) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 515 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)( |
michael@0 | 516 | const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 517 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)( |
michael@0 | 518 | const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 519 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)( |
michael@0 | 520 | const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 521 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)( |
michael@0 | 522 | const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 523 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)( |
michael@0 | 524 | const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 525 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)( |
michael@0 | 526 | const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 527 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)( |
michael@0 | 528 | const char *file, int line, int enable) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 529 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)( |
michael@0 | 530 | const char *file, int line, |
michael@0 | 531 | const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 532 | void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)( |
michael@0 | 533 | const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 534 | |
michael@0 | 535 | #if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 |
michael@0 | 536 | /* Return non-zero value if running under valgrind. |
michael@0 | 537 | |
michael@0 | 538 | If "valgrind.h" is included into dynamic_annotations.c, |
michael@0 | 539 | the regular valgrind mechanism will be used. |
michael@0 | 540 | See http://valgrind.org/docs/manual/manual-core-adv.html about |
michael@0 | 541 | RUNNING_ON_VALGRIND and other valgrind "client requests". |
michael@0 | 542 | The file "valgrind.h" may be obtained by doing |
michael@0 | 543 | svn co svn://svn.valgrind.org/valgrind/trunk/include |
michael@0 | 544 | |
michael@0 | 545 | If for some reason you can't use "valgrind.h" or want to fake valgrind, |
michael@0 | 546 | there are two ways to make this function return non-zero: |
michael@0 | 547 | - Use environment variable: export RUNNING_ON_VALGRIND=1 |
michael@0 | 548 | - Make your tool intercept the function RunningOnValgrind() and |
michael@0 | 549 | change its return value. |
michael@0 | 550 | */ |
michael@0 | 551 | int RunningOnValgrind(void) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; |
michael@0 | 552 | #endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */ |
michael@0 | 553 | |
michael@0 | 554 | #ifdef __cplusplus |
michael@0 | 555 | } |
michael@0 | 556 | #endif |
michael@0 | 557 | |
michael@0 | 558 | #if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) |
michael@0 | 559 | |
michael@0 | 560 | /* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. |
michael@0 | 561 | |
michael@0 | 562 | Instead of doing |
michael@0 | 563 | ANNOTATE_IGNORE_READS_BEGIN(); |
michael@0 | 564 | ... = x; |
michael@0 | 565 | ANNOTATE_IGNORE_READS_END(); |
michael@0 | 566 | one can use |
michael@0 | 567 | ... = ANNOTATE_UNPROTECTED_READ(x); */ |
michael@0 | 568 | template <class T> |
michael@0 | 569 | inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) { |
michael@0 | 570 | ANNOTATE_IGNORE_READS_BEGIN(); |
michael@0 | 571 | T res = x; |
michael@0 | 572 | ANNOTATE_IGNORE_READS_END(); |
michael@0 | 573 | return res; |
michael@0 | 574 | } |
michael@0 | 575 | /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ |
michael@0 | 576 | #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ |
michael@0 | 577 | namespace { \ |
michael@0 | 578 | class static_var ## _annotator { \ |
michael@0 | 579 | public: \ |
michael@0 | 580 | static_var ## _annotator() { \ |
michael@0 | 581 | ANNOTATE_BENIGN_RACE_SIZED(&static_var, \ |
michael@0 | 582 | sizeof(static_var), \ |
michael@0 | 583 | # static_var ": " description); \ |
michael@0 | 584 | } \ |
michael@0 | 585 | }; \ |
michael@0 | 586 | static static_var ## _annotator the ## static_var ## _annotator;\ |
michael@0 | 587 | } |
michael@0 | 588 | #else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ |
michael@0 | 589 | |
michael@0 | 590 | #define ANNOTATE_UNPROTECTED_READ(x) (x) |
michael@0 | 591 | #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */ |
michael@0 | 592 | |
michael@0 | 593 | #endif /* DYNAMIC_ANNOTATIONS_ENABLED */ |
michael@0 | 594 | |
michael@0 | 595 | #endif /* __DYNAMIC_ANNOTATIONS_H__ */ |