linux-kernel.cat 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // SPDX-License-Identifier: GPL-2.0+
  2. (*
  3. * Copyright (C) 2015 Jade Alglave <j.alglave@ucl.ac.uk>,
  4. * Copyright (C) 2016 Luc Maranget <luc.maranget@inria.fr> for Inria
  5. * Copyright (C) 2017 Alan Stern <stern@rowland.harvard.edu>,
  6. * Andrea Parri <parri.andrea@gmail.com>
  7. *
  8. * An earlier version of this file appeared in the companion webpage for
  9. * "Frightening small children and disconcerting grown-ups: Concurrency
  10. * in the Linux kernel" by Alglave, Maranget, McKenney, Parri, and Stern,
  11. * which appeared in ASPLOS 2018.
  12. *)
  13. "Linux-kernel memory consistency model"
  14. (*
  15. * File "lock.cat" handles locks and is experimental.
  16. * It can be replaced by include "cos.cat" for tests that do not use locks.
  17. *)
  18. include "lock.cat"
  19. (*******************)
  20. (* Basic relations *)
  21. (*******************)
  22. (* Release Acquire *)
  23. let acq-po = [Acquire] ; po ; [M]
  24. let po-rel = [M] ; po ; [Release]
  25. let po-unlock-lock-po = po ; [UL] ; (po|rf) ; [LKR] ; po
  26. (* Fences *)
  27. let R4rmb = R \ Noreturn (* Reads for which rmb works *)
  28. let rmb = [R4rmb] ; fencerel(Rmb) ; [R4rmb]
  29. let wmb = [W] ; fencerel(Wmb) ; [W]
  30. let mb = ([M] ; fencerel(Mb) ; [M]) |
  31. (*
  32. * full-barrier RMWs (successful cmpxchg(), xchg(), etc.) act as
  33. * though there were enclosed by smp_mb().
  34. * The effect of these virtual smp_mb() is formalized by adding
  35. * Mb tags to the read and write of the operation, and providing
  36. * the same ordering as though there were additional po edges
  37. * between the Mb tag and the read resp. write.
  38. *)
  39. ([M] ; po ; [Mb & R]) |
  40. ([Mb & W] ; po ; [M]) |
  41. ([M] ; fencerel(Before-atomic) ; [RMW] ; po? ; [M]) |
  42. ([M] ; po? ; [RMW] ; fencerel(After-atomic) ; [M]) |
  43. ([M] ; po? ; [LKW] ; fencerel(After-spinlock) ; [M]) |
  44. (*
  45. * Note: The po-unlock-lock-po relation only passes the lock to the direct
  46. * successor, perhaps giving the impression that the ordering of the
  47. * smp_mb__after_unlock_lock() fence only affects a single lock handover.
  48. * However, in a longer sequence of lock handovers, the implicit
  49. * A-cumulative release fences of lock-release ensure that any stores that
  50. * propagate to one of the involved CPUs before it hands over the lock to
  51. * the next CPU will also propagate to the final CPU handing over the lock
  52. * to the CPU that executes the fence. Therefore, all those stores are
  53. * also affected by the fence.
  54. *)
  55. ([M] ; po-unlock-lock-po ;
  56. [After-unlock-lock] ; po ; [M]) |
  57. ([M] ; po? ; [Srcu-unlock] ; fencerel(After-srcu-read-unlock) ; [M])
  58. let gp = po ; [Sync-rcu | Sync-srcu] ; po?
  59. let strong-fence = mb | gp
  60. let nonrw-fence = strong-fence | po-rel | acq-po
  61. let fence = nonrw-fence | wmb | rmb
  62. let barrier = fencerel(Barrier | Rmb | Wmb | Mb | Sync-rcu | Sync-srcu |
  63. Before-atomic | After-atomic | Acquire | Release |
  64. Rcu-lock | Rcu-unlock | Srcu-lock | Srcu-unlock) |
  65. (po ; [Release]) | ([Acquire] ; po)
  66. (**********************************)
  67. (* Fundamental coherence ordering *)
  68. (**********************************)
  69. (* Sequential Consistency Per Variable *)
  70. let com = rf | co | fr
  71. acyclic po-loc | com as coherence
  72. (* Atomic Read-Modify-Write *)
  73. empty rmw & (fre ; coe) as atomic
  74. (**********************************)
  75. (* Instruction execution ordering *)
  76. (**********************************)
  77. (* Preserved Program Order *)
  78. let dep = addr | data
  79. let rwdep = (dep | ctrl) ; [W]
  80. let overwrite = co | fr
  81. let to-w = rwdep | (overwrite & int) | (addr ; [Plain] ; wmb)
  82. let to-r = (addr ; [R]) | (dep ; [Marked] ; rfi)
  83. let ppo = to-r | to-w | (fence & int) | (po-unlock-lock-po & int)
  84. (* Propagation: Ordering from release operations and strong fences. *)
  85. let A-cumul(r) = (rfe ; [Marked])? ; r
  86. let rmw-sequence = (rf ; rmw)*
  87. let cumul-fence = [Marked] ; (A-cumul(strong-fence | po-rel) | wmb |
  88. po-unlock-lock-po) ; [Marked] ; rmw-sequence
  89. let prop = [Marked] ; (overwrite & ext)? ; cumul-fence* ;
  90. [Marked] ; rfe? ; [Marked]
  91. (*
  92. * Happens Before: Ordering from the passage of time.
  93. * No fences needed here for prop because relation confined to one process.
  94. *)
  95. let hb = [Marked] ; (ppo | rfe | ((prop \ id) & int)) ; [Marked]
  96. acyclic hb as happens-before
  97. (****************************************)
  98. (* Write and fence propagation ordering *)
  99. (****************************************)
  100. (* Propagation: Each non-rf link needs a strong fence. *)
  101. let pb = prop ; strong-fence ; hb* ; [Marked]
  102. acyclic pb as propagation
  103. (*******)
  104. (* RCU *)
  105. (*******)
  106. (*
  107. * Effects of read-side critical sections proceed from the rcu_read_unlock()
  108. * or srcu_read_unlock() backwards on the one hand, and from the
  109. * rcu_read_lock() or srcu_read_lock() forwards on the other hand.
  110. *
  111. * In the definition of rcu-fence below, the po term at the left-hand side
  112. * of each disjunct and the po? term at the right-hand end have been factored
  113. * out. They have been moved into the definitions of rcu-link and rb.
  114. * This was necessary in order to apply the "& loc" tests correctly.
  115. *)
  116. let rcu-gp = [Sync-rcu] (* Compare with gp *)
  117. let srcu-gp = [Sync-srcu]
  118. let rcu-rscsi = rcu-rscs^-1
  119. let srcu-rscsi = srcu-rscs^-1
  120. (*
  121. * The synchronize_rcu() strong fence is special in that it can order not
  122. * one but two non-rf relations, but only in conjunction with an RCU
  123. * read-side critical section.
  124. *)
  125. let rcu-link = po? ; hb* ; pb* ; prop ; po
  126. (*
  127. * Any sequence containing at least as many grace periods as RCU read-side
  128. * critical sections (joined by rcu-link) induces order like a generalized
  129. * inter-CPU strong fence.
  130. * Likewise for SRCU grace periods and read-side critical sections, provided
  131. * the synchronize_srcu() and srcu_read_[un]lock() calls refer to the same
  132. * struct srcu_struct location.
  133. *)
  134. let rec rcu-order = rcu-gp | srcu-gp |
  135. (rcu-gp ; rcu-link ; rcu-rscsi) |
  136. ((srcu-gp ; rcu-link ; srcu-rscsi) & loc) |
  137. (rcu-rscsi ; rcu-link ; rcu-gp) |
  138. ((srcu-rscsi ; rcu-link ; srcu-gp) & loc) |
  139. (rcu-gp ; rcu-link ; rcu-order ; rcu-link ; rcu-rscsi) |
  140. ((srcu-gp ; rcu-link ; rcu-order ; rcu-link ; srcu-rscsi) & loc) |
  141. (rcu-rscsi ; rcu-link ; rcu-order ; rcu-link ; rcu-gp) |
  142. ((srcu-rscsi ; rcu-link ; rcu-order ; rcu-link ; srcu-gp) & loc) |
  143. (rcu-order ; rcu-link ; rcu-order)
  144. let rcu-fence = po ; rcu-order ; po?
  145. let fence = fence | rcu-fence
  146. let strong-fence = strong-fence | rcu-fence
  147. (* rb orders instructions just as pb does *)
  148. let rb = prop ; rcu-fence ; hb* ; pb* ; [Marked]
  149. irreflexive rb as rcu
  150. (*
  151. * The happens-before, propagation, and rcu constraints are all
  152. * expressions of temporal ordering. They could be replaced by
  153. * a single constraint on an "executes-before" relation, xb:
  154. *
  155. * let xb = hb | pb | rb
  156. * acyclic xb as executes-before
  157. *)
  158. (*********************************)
  159. (* Plain accesses and data races *)
  160. (*********************************)
  161. (* Warn about plain writes and marked accesses in the same region *)
  162. let mixed-accesses = ([Plain & W] ; (po-loc \ barrier) ; [Marked]) |
  163. ([Marked] ; (po-loc \ barrier) ; [Plain & W])
  164. flag ~empty mixed-accesses as mixed-accesses
  165. (* Executes-before and visibility *)
  166. let xbstar = (hb | pb | rb)*
  167. let vis = cumul-fence* ; rfe? ; [Marked] ;
  168. ((strong-fence ; [Marked] ; xbstar) | (xbstar & int))
  169. (* Boundaries for lifetimes of plain accesses *)
  170. let w-pre-bounded = [Marked] ; (addr | fence)?
  171. let r-pre-bounded = [Marked] ; (addr | nonrw-fence |
  172. ([R4rmb] ; fencerel(Rmb) ; [~Noreturn]))?
  173. let w-post-bounded = fence? ; [Marked] ; rmw-sequence
  174. let r-post-bounded = (nonrw-fence | ([~Noreturn] ; fencerel(Rmb) ; [R4rmb]))? ;
  175. [Marked]
  176. (* Visibility and executes-before for plain accesses *)
  177. let ww-vis = fence | (strong-fence ; xbstar ; w-pre-bounded) |
  178. (w-post-bounded ; vis ; w-pre-bounded)
  179. let wr-vis = fence | (strong-fence ; xbstar ; r-pre-bounded) |
  180. (w-post-bounded ; vis ; r-pre-bounded)
  181. let rw-xbstar = fence | (r-post-bounded ; xbstar ; w-pre-bounded)
  182. (* Potential races *)
  183. let pre-race = ext & ((Plain * M) | ((M \ IW) * Plain))
  184. (* Coherence requirements for plain accesses *)
  185. let wr-incoh = pre-race & rf & rw-xbstar^-1
  186. let rw-incoh = pre-race & fr & wr-vis^-1
  187. let ww-incoh = pre-race & co & ww-vis^-1
  188. empty (wr-incoh | rw-incoh | ww-incoh) as plain-coherence
  189. (* Actual races *)
  190. let ww-nonrace = ww-vis & ((Marked * W) | rw-xbstar) & ((W * Marked) | wr-vis)
  191. let ww-race = (pre-race & co) \ ww-nonrace
  192. let wr-race = (pre-race & (co? ; rf)) \ wr-vis \ rw-xbstar^-1
  193. let rw-race = (pre-race & fr) \ rw-xbstar
  194. flag ~empty (ww-race | wr-race | rw-race) as data-race