1# Zircon thread safety annotations 2 3Zircon code takes advantage of clang's thread safety analysis feature to 4document and machine-verify some of our synchronization invariants. These 5annotations are checked when building for clang (see 6[getting started](getting_started.md) for instructions on building with 7clang). 8 9## How to use 10 11[Clang's documentation](https://clang.llvm.org/docs/ThreadSafetyAnalysis.html) 12 13In Zircon, we provide our own set of macros wrapping the annotations and have 14annotated our synchronization primitives. When writing new code involving 15synchronization or annotating existing code, in most cases you should use the 16thread annotation macros provided by 17[system/private/zircon/thread\_annotations.h](../system/private/zircon/thread_annotations.h). These macros all begin with 18the prefix `"TA_"` for thread analysis. The most commonly used ones are: 19 20* `TA_GUARDED(x)` the annotated variable is guarded by the capability (e.g. lock) `x` 21* `TA_ACQ(x...)` function acquires all of the mutexes in the set `x` and hold them after returning 22* `TA_REL(x...)` function releases all of the mutexes in the set `x` 23* `TA_REQ(x...)` function requires that the caller hold all of the mutexes in the set `x` 24* `TA_EXCL(x...)` function requires that the caller not be holding any of the mutexes in the set `x` 25 26For example, a class containing a member variable `'int foo_'` protected by a 27mutex would be annotated like so: 28 29``` 30// example.h 31 32class Example { 33public: 34 // Public function has no locking requirements and thus needs no annotation. 35 int IncreaseFoo(int by); 36 37private: 38 // This is an internal helper routine that can only be called with |lock_| 39 // held. Calling this without holding |lock_| is a compile-time error. 40 // Annotations like TA_REQ, TA_ACQ, TA_REL, etc are part of the function's 41 // interface and must be on the function declaration, usually in the header, 42 // not the definition. 43 int IncreaseFooLocked(int by) TA_REQ(lock_); 44 45 // This internal routine requires that both |lock_| and |foo_lock_| be held by the 46 // caller. 47 int IncreaseFooAndBarLocked(int foo_by, int bar_by) TA_REQ(lock_) TA_REQ(bar_lock_); 48 49 // The TA_GUARDED(lock_) annotation on |foo_| means that |lock_| must be 50 // held to read or write from |foo_|. 51 int foo_ TA_GUARDED(lock_); 52 53 // |lock_| can be declared after annotations referencing it, 54 // if desired. 55 Mutex lock_; 56 57 Mutex bar_lock_; 58}; 59 60// example.cpp 61 62int Example::IncreaseFoo(int by) { 63 int new_value; 64 { 65 AutoLock lock(&lock_); // fbl::AutoLock is annotated 66 new_value = IncreaseFooLocked(by); 67 } 68 return new_value; 69} 70``` 71 72Note that for annotations which allow sets of mutex objects, one may either 73apply the annotation multiple times, or provided a comma separated list to the 74annotation. In other words, the following two declarations are equivalent. 75 76``` 77 int IncreaseFooAndBarLocked(int foo_by, int bar_by) TA_REQ(lock_) TA_REQ(bar_lock_); 78 int IncreaseFooAndBarLocked(int foo_by, int bar_by) TA_REQ(lock_, bar_lock_); 79``` 80 81Library code exposed through the sysroot must use the more awkwardly named 82macros provided by 83[system/public/zircon/compiler.h](../system/public/zircon/compiler.h) to 84avoid collisions with consumers of the sysroot. 85 86## Best practices 87 88Annotations should complement the comments and identifiers to make the code 89understandable. Annotations do not replace comments or clear names. Try to 90follow these best practices when writing code involving locking: 91 92* Group member variables protected by a lock with the lock. Where it makes 93sense, document what is protected by what with a comment in addition to the 94annotations. For example when several member variables are protected by one lock 95and several are protected by a different lock, a comment is easier to read than 96going through each annotation. 97 98* Name functions that require a lock be held with a 'Locked()' suffix. If there 99are multiple locks that could be plausibly held to call the function, consider 100making the choice clear in the function name. Keep in mind readers of calling 101code will not be able to see the annotations. 102 103## Limitations 104 105The thread safety analysis is a purely static check done at compile time and 106cannot understand conditionally held locks or locking patterns that span 107compilation units in ways not expressible via static annotations. In many 108situations, this analysis is still useful but there are situations that the 109analysis simply cannot understand. The main escape hatch for disabling analysis 110is to add the annotation `TA_NO_THREAD_SAFETY_ANALYSIS` to the function definition 111containing the code the analysis is confused by. Other escape mechanisms are 112available as well - see the Clang documentation for details. Situations that 113require disabling the analysis are likely to be complex for humans to understand 114as well as machines and should be accompanied by a comment indicating the 115invariants in use. 116 117The thread safety analysis can be defeated in a number of ways, for instance 118when using pointers. For example, when taking the address of a guarded data 119member Clang looses track of the guard, e.g. for a foo_ protected by a lock_ 120a call to `memset(&foo_, 0, sizeof(foo_))` without holding lock_ won't be caught 121as a violation. 122