diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2018-11-15 11:20:37 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.ibm.com> | 2019-03-18 13:27:52 -0400 |
commit | a3f600d92da564ad35f237c8aeab268ca49377cc (patch) | |
tree | 8b5cbb5e49d7b0556f2fdd1faf9667810c4d1941 /tools/memory-model | |
parent | 284749b0aebbf3ab26ff92198545aea36165f6bf (diff) |
tools/memory-model: Add SRCU support
Add support for SRCU. Herd creates srcu events and linux-kernel.def
associates them with three possible annotations (srcu-lock,
srcu-unlock, and sync-srcu) corresponding to the API routines
srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu().
The linux-kernel.bell file now declares the annotations
and determines matching lock/unlock pairs delimiting SRCU read-side
critical sections, and it also checks for synchronize_srcu() calls
inside an RCU critical section (which would generate a "sleeping in
atomic context" error in real kernel code). The linux-kernel.cat file
now adds SRCU-induced ordering, analogous to the existing RCU-induced
ordering, to the gp and rcu-fence relations.
Curiously enough, these small changes to the model's .cat code are all
that is needed to describe SRCU.
Portions of this patch (linux-kernel.def and the first hunk in
linux-kernel.bell) were written by Luc Maranget.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Luc Maranget <luc.maranget@inria.fr>
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
Tested-by: Andrea Parri <andrea.parri@amarulasolutions.com>
Diffstat (limited to 'tools/memory-model')
-rw-r--r-- | tools/memory-model/linux-kernel.bell | 25 | ||||
-rw-r--r-- | tools/memory-model/linux-kernel.cat | 18 | ||||
-rw-r--r-- | tools/memory-model/linux-kernel.def | 5 |
3 files changed, 44 insertions, 4 deletions
diff --git a/tools/memory-model/linux-kernel.bell b/tools/memory-model/linux-kernel.bell index 353c8d68e030..9c42cd9ddcb4 100644 --- a/tools/memory-model/linux-kernel.bell +++ b/tools/memory-model/linux-kernel.bell | |||
@@ -33,6 +33,12 @@ enum Barriers = 'wmb (*smp_wmb*) || | |||
33 | 'after-unlock-lock (*smp_mb__after_unlock_lock*) | 33 | 'after-unlock-lock (*smp_mb__after_unlock_lock*) |
34 | instructions F[Barriers] | 34 | instructions F[Barriers] |
35 | 35 | ||
36 | (* SRCU *) | ||
37 | enum SRCU = 'srcu-lock || 'srcu-unlock || 'sync-srcu | ||
38 | instructions SRCU[SRCU] | ||
39 | (* All srcu events *) | ||
40 | let Srcu = Srcu-lock | Srcu-unlock | Sync-srcu | ||
41 | |||
36 | (* Compute matching pairs of nested Rcu-lock and Rcu-unlock *) | 42 | (* Compute matching pairs of nested Rcu-lock and Rcu-unlock *) |
37 | let rcu-rscs = let rec | 43 | let rcu-rscs = let rec |
38 | unmatched-locks = Rcu-lock \ domain(matched) | 44 | unmatched-locks = Rcu-lock \ domain(matched) |
@@ -48,3 +54,22 @@ let rcu-rscs = let rec | |||
48 | (* Validate nesting *) | 54 | (* Validate nesting *) |
49 | flag ~empty Rcu-lock \ domain(rcu-rscs) as unbalanced-rcu-locking | 55 | flag ~empty Rcu-lock \ domain(rcu-rscs) as unbalanced-rcu-locking |
50 | flag ~empty Rcu-unlock \ range(rcu-rscs) as unbalanced-rcu-locking | 56 | flag ~empty Rcu-unlock \ range(rcu-rscs) as unbalanced-rcu-locking |
57 | |||
58 | (* Compute matching pairs of nested Srcu-lock and Srcu-unlock *) | ||
59 | let srcu-rscs = let rec | ||
60 | unmatched-locks = Srcu-lock \ domain(matched) | ||
61 | and unmatched-unlocks = Srcu-unlock \ range(matched) | ||
62 | and unmatched = unmatched-locks | unmatched-unlocks | ||
63 | and unmatched-po = ([unmatched] ; po ; [unmatched]) & loc | ||
64 | and unmatched-locks-to-unlocks = | ||
65 | ([unmatched-locks] ; po ; [unmatched-unlocks]) & loc | ||
66 | and matched = matched | (unmatched-locks-to-unlocks \ | ||
67 | (unmatched-po ; unmatched-po)) | ||
68 | in matched | ||
69 | |||
70 | (* Validate nesting *) | ||
71 | flag ~empty Srcu-lock \ domain(srcu-rscs) as unbalanced-srcu-locking | ||
72 | flag ~empty Srcu-unlock \ range(srcu-rscs) as unbalanced-srcu-locking | ||
73 | |||
74 | (* Check for use of synchronize_srcu() inside an RCU critical section *) | ||
75 | flag ~empty rcu-rscs & (po ; [Sync-srcu] ; po) as invalid-sleep | ||
diff --git a/tools/memory-model/linux-kernel.cat b/tools/memory-model/linux-kernel.cat index b8e6197f05af..8dcb37835b61 100644 --- a/tools/memory-model/linux-kernel.cat +++ b/tools/memory-model/linux-kernel.cat | |||
@@ -33,7 +33,7 @@ let mb = ([M] ; fencerel(Mb) ; [M]) | | |||
33 | ([M] ; po? ; [LKW] ; fencerel(After-spinlock) ; [M]) | | 33 | ([M] ; po? ; [LKW] ; fencerel(After-spinlock) ; [M]) | |
34 | ([M] ; po ; [UL] ; (co | po) ; [LKW] ; | 34 | ([M] ; po ; [UL] ; (co | po) ; [LKW] ; |
35 | fencerel(After-unlock-lock) ; [M]) | 35 | fencerel(After-unlock-lock) ; [M]) |
36 | let gp = po ; [Sync-rcu] ; po? | 36 | let gp = po ; [Sync-rcu | Sync-srcu] ; po? |
37 | 37 | ||
38 | let strong-fence = mb | gp | 38 | let strong-fence = mb | gp |
39 | 39 | ||
@@ -92,15 +92,18 @@ acyclic pb as propagation | |||
92 | 92 | ||
93 | (* | 93 | (* |
94 | * Effects of read-side critical sections proceed from the rcu_read_unlock() | 94 | * Effects of read-side critical sections proceed from the rcu_read_unlock() |
95 | * backwards on the one hand, and from the rcu_read_lock() forwards on the | 95 | * or srcu_read_unlock() backwards on the one hand, and from the |
96 | * other hand. | 96 | * rcu_read_lock() or srcu_read_lock() forwards on the other hand. |
97 | * | 97 | * |
98 | * In the definition of rcu-fence below, the po term at the left-hand side | 98 | * In the definition of rcu-fence below, the po term at the left-hand side |
99 | * of each disjunct and the po? term at the right-hand end have been factored | 99 | * of each disjunct and the po? term at the right-hand end have been factored |
100 | * out. They have been moved into the definitions of rcu-link and rb. | 100 | * out. They have been moved into the definitions of rcu-link and rb. |
101 | * This was necessary in order to apply the "& loc" tests correctly. | ||
101 | *) | 102 | *) |
102 | let rcu-gp = [Sync-rcu] (* Compare with gp *) | 103 | let rcu-gp = [Sync-rcu] (* Compare with gp *) |
104 | let srcu-gp = [Sync-srcu] | ||
103 | let rcu-rscsi = rcu-rscs^-1 | 105 | let rcu-rscsi = rcu-rscs^-1 |
106 | let srcu-rscsi = srcu-rscs^-1 | ||
104 | 107 | ||
105 | (* | 108 | (* |
106 | * The synchronize_rcu() strong fence is special in that it can order not | 109 | * The synchronize_rcu() strong fence is special in that it can order not |
@@ -112,12 +115,19 @@ let rcu-link = po? ; hb* ; pb* ; prop ; po | |||
112 | (* | 115 | (* |
113 | * Any sequence containing at least as many grace periods as RCU read-side | 116 | * Any sequence containing at least as many grace periods as RCU read-side |
114 | * critical sections (joined by rcu-link) acts as a generalized strong fence. | 117 | * critical sections (joined by rcu-link) acts as a generalized strong fence. |
118 | * Likewise for SRCU grace periods and read-side critical sections, provided | ||
119 | * the synchronize_srcu() and srcu_read_[un]lock() calls refer to the same | ||
120 | * struct srcu_struct location. | ||
115 | *) | 121 | *) |
116 | let rec rcu-fence = rcu-gp | | 122 | let rec rcu-fence = rcu-gp | srcu-gp | |
117 | (rcu-gp ; rcu-link ; rcu-rscsi) | | 123 | (rcu-gp ; rcu-link ; rcu-rscsi) | |
124 | ((srcu-gp ; rcu-link ; srcu-rscsi) & loc) | | ||
118 | (rcu-rscsi ; rcu-link ; rcu-gp) | | 125 | (rcu-rscsi ; rcu-link ; rcu-gp) | |
126 | ((srcu-rscsi ; rcu-link ; srcu-gp) & loc) | | ||
119 | (rcu-gp ; rcu-link ; rcu-fence ; rcu-link ; rcu-rscsi) | | 127 | (rcu-gp ; rcu-link ; rcu-fence ; rcu-link ; rcu-rscsi) | |
128 | ((srcu-gp ; rcu-link ; rcu-fence ; rcu-link ; srcu-rscsi) & loc) | | ||
120 | (rcu-rscsi ; rcu-link ; rcu-fence ; rcu-link ; rcu-gp) | | 129 | (rcu-rscsi ; rcu-link ; rcu-fence ; rcu-link ; rcu-gp) | |
130 | ((srcu-rscsi ; rcu-link ; rcu-fence ; rcu-link ; srcu-gp) & loc) | | ||
121 | (rcu-fence ; rcu-link ; rcu-fence) | 131 | (rcu-fence ; rcu-link ; rcu-fence) |
122 | 132 | ||
123 | (* rb orders instructions just as pb does *) | 133 | (* rb orders instructions just as pb does *) |
diff --git a/tools/memory-model/linux-kernel.def b/tools/memory-model/linux-kernel.def index b27911cc087d..1d6a120cde14 100644 --- a/tools/memory-model/linux-kernel.def +++ b/tools/memory-model/linux-kernel.def | |||
@@ -47,6 +47,11 @@ rcu_read_unlock() { __fence{rcu-unlock}; } | |||
47 | synchronize_rcu() { __fence{sync-rcu}; } | 47 | synchronize_rcu() { __fence{sync-rcu}; } |
48 | synchronize_rcu_expedited() { __fence{sync-rcu}; } | 48 | synchronize_rcu_expedited() { __fence{sync-rcu}; } |
49 | 49 | ||
50 | // SRCU | ||
51 | srcu_read_lock(X) __srcu{srcu-lock}(X) | ||
52 | srcu_read_unlock(X,Y) { __srcu{srcu-unlock}(X); } | ||
53 | synchronize_srcu(X) { __srcu{sync-srcu}(X); } | ||
54 | |||
50 | // Atomic | 55 | // Atomic |
51 | atomic_read(X) READ_ONCE(*X) | 56 | atomic_read(X) READ_ONCE(*X) |
52 | atomic_set(X,V) { WRITE_ONCE(*X,V); } | 57 | atomic_set(X,V) { WRITE_ONCE(*X,V); } |