summaryrefslogtreecommitdiffstats
path: root/tools/memory-model
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2018-11-15 11:20:37 -0500
committerPaul E. McKenney <paulmck@linux.ibm.com>2019-03-18 13:27:52 -0400
commita3f600d92da564ad35f237c8aeab268ca49377cc (patch)
tree8b5cbb5e49d7b0556f2fdd1faf9667810c4d1941 /tools/memory-model
parent284749b0aebbf3ab26ff92198545aea36165f6bf (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.bell25
-rw-r--r--tools/memory-model/linux-kernel.cat18
-rw-r--r--tools/memory-model/linux-kernel.def5
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*)
34instructions F[Barriers] 34instructions F[Barriers]
35 35
36(* SRCU *)
37enum SRCU = 'srcu-lock || 'srcu-unlock || 'sync-srcu
38instructions SRCU[SRCU]
39(* All srcu events *)
40let 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 *)
37let rcu-rscs = let rec 43let 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 *)
49flag ~empty Rcu-lock \ domain(rcu-rscs) as unbalanced-rcu-locking 55flag ~empty Rcu-lock \ domain(rcu-rscs) as unbalanced-rcu-locking
50flag ~empty Rcu-unlock \ range(rcu-rscs) as unbalanced-rcu-locking 56flag ~empty Rcu-unlock \ range(rcu-rscs) as unbalanced-rcu-locking
57
58(* Compute matching pairs of nested Srcu-lock and Srcu-unlock *)
59let 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 *)
71flag ~empty Srcu-lock \ domain(srcu-rscs) as unbalanced-srcu-locking
72flag ~empty Srcu-unlock \ range(srcu-rscs) as unbalanced-srcu-locking
73
74(* Check for use of synchronize_srcu() inside an RCU critical section *)
75flag ~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])
36let gp = po ; [Sync-rcu] ; po? 36let gp = po ; [Sync-rcu | Sync-srcu] ; po?
37 37
38let strong-fence = mb | gp 38let 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 *)
102let rcu-gp = [Sync-rcu] (* Compare with gp *) 103let rcu-gp = [Sync-rcu] (* Compare with gp *)
104let srcu-gp = [Sync-srcu]
103let rcu-rscsi = rcu-rscs^-1 105let rcu-rscsi = rcu-rscs^-1
106let 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 *)
116let rec rcu-fence = rcu-gp | 122let 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}; }
47synchronize_rcu() { __fence{sync-rcu}; } 47synchronize_rcu() { __fence{sync-rcu}; }
48synchronize_rcu_expedited() { __fence{sync-rcu}; } 48synchronize_rcu_expedited() { __fence{sync-rcu}; }
49 49
50// SRCU
51srcu_read_lock(X) __srcu{srcu-lock}(X)
52srcu_read_unlock(X,Y) { __srcu{srcu-unlock}(X); }
53synchronize_srcu(X) { __srcu{sync-srcu}(X); }
54
50// Atomic 55// Atomic
51atomic_read(X) READ_ONCE(*X) 56atomic_read(X) READ_ONCE(*X)
52atomic_set(X,V) { WRITE_ONCE(*X,V); } 57atomic_set(X,V) { WRITE_ONCE(*X,V); }