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