linux-kernel.cat 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. ([M] ; fencerel(Before-atomic) ; [RMW] ; po? ; [M]) |
  32. ([M] ; po? ; [RMW] ; fencerel(After-atomic) ; [M]) |
  33. ([M] ; po? ; [LKW] ; fencerel(After-spinlock) ; [M]) |
  34. (*
  35. * Note: The po-unlock-lock-po relation only passes the lock to the direct
  36. * successor, perhaps giving the impression that the ordering of the
  37. * smp_mb__after_unlock_lock() fence only affects a single lock handover.
  38. * However, in a longer sequence of lock handovers, the implicit
  39. * A-cumulative release fences of lock-release ensure that any stores that
  40. * propagate to one of the involved CPUs before it hands over the lock to
  41. * the next CPU will also propagate to the final CPU handing over the lock
  42. * to the CPU that executes the fence. Therefore, all those stores are
  43. * also affected by the fence.
  44. *)
  45. ([M] ; po-unlock-lock-po ;
  46. [After-unlock-lock] ; po ; [M]) |
  47. ([M] ; po? ; [Srcu-unlock] ; fencerel(After-srcu-read-unlock) ; [M])
  48. let gp = po ; [Sync-rcu | Sync-srcu] ; po?
  49. let strong-fence = mb | gp
  50. let nonrw-fence = strong-fence | po-rel | acq-po
  51. let fence = nonrw-fence | wmb | rmb
  52. let barrier = fencerel(Barrier | Rmb | Wmb | Mb | Sync-rcu | Sync-srcu |
  53. Before-atomic | After-atomic | Acquire | Release |
  54. Rcu-lock | Rcu-unlock | Srcu-lock | Srcu-unlock) |
  55. (po ; [Release]) | ([Acquire] ; po)
  56. (**********************************)
  57. (* Fundamental coherence ordering *)
  58. (**********************************)
  59. (* Sequential Consistency Per Variable *)
  60. let com = rf | co | fr
  61. acyclic po-loc | com as coherence
  62. (* Atomic Read-Modify-Write *)
  63. empty rmw & (fre ; coe) as atomic
  64. (**********************************)
  65. (* Instruction execution ordering *)
  66. (**********************************)
  67. (* Preserved Program Order *)
  68. let dep = addr | data
  69. let rwdep = (dep | ctrl) ; [W]
  70. let overwrite = co | fr
  71. let to-w = rwdep | (overwrite & int) | (addr ; [Plain] ; wmb)
  72. let to-r = (addr ; [R]) | (dep ; [Marked] ; rfi)
  73. let ppo = to-r | to-w | (fence & int) | (po-unlock-lock-po & int)
  74. (* Propagation: Ordering from release operations and strong fences. *)
  75. let A-cumul(r) = (rfe ; [Marked])? ; r
  76. let rmw-sequence = (rf ; rmw)*
  77. let cumul-fence = [Marked] ; (A-cumul(strong-fence | po-rel) | wmb |
  78. po-unlock-lock-po) ; [Marked] ; rmw-sequence
  79. let prop = [Marked] ; (overwrite & ext)? ; cumul-fence* ;
  80. [Marked] ; rfe? ; [Marked]
  81. (*
  82. * Happens Before: Ordering from the passage of time.
  83. * No fences needed here for prop because relation confined to one process.
  84. *)
  85. let hb = [Marked] ; (ppo | rfe | ((prop \ id) & int)) ; [Marked]
  86. acyclic hb as happens-before
  87. (****************************************)
  88. (* Write and fence propagation ordering *)
  89. (****************************************)
  90. (* Propagation: Each non-rf link needs a strong fence. *)
  91. let pb = prop ; strong-fence ; hb* ; [Marked]
  92. acyclic pb as propagation
  93. (*******)
  94. (* RCU *)
  95. (*******)
  96. (*
  97. * Effects of read-side critical sections proceed from the rcu_read_unlock()
  98. * or srcu_read_unlock() backwards on the one hand, and from the
  99. * rcu_read_lock() or srcu_read_lock() forwards on the other hand.
  100. *
  101. * In the definition of rcu-fence below, the po term at the left-hand side
  102. * of each disjunct and the po? term at the right-hand end have been factored
  103. * out. They have been moved into the definitions of rcu-link and rb.
  104. * This was necessary in order to apply the "& loc" tests correctly.
  105. *)
  106. let rcu-gp = [Sync-rcu] (* Compare with gp *)
  107. let srcu-gp = [Sync-srcu]
  108. let rcu-rscsi = rcu-rscs^-1
  109. let srcu-rscsi = srcu-rscs^-1
  110. (*
  111. * The synchronize_rcu() strong fence is special in that it can order not
  112. * one but two non-rf relations, but only in conjunction with an RCU
  113. * read-side critical section.
  114. *)
  115. let rcu-link = po? ; hb* ; pb* ; prop ; po
  116. (*
  117. * Any sequence containing at least as many grace periods as RCU read-side
  118. * critical sections (joined by rcu-link) induces order like a generalized
  119. * inter-CPU strong fence.
  120. * Likewise for SRCU grace periods and read-side critical sections, provided
  121. * the synchronize_srcu() and srcu_read_[un]lock() calls refer to the same
  122. * struct srcu_struct location.
  123. *)
  124. let rec rcu-order = rcu-gp | srcu-gp |
  125. (rcu-gp ; rcu-link ; rcu-rscsi) |
  126. ((srcu-gp ; rcu-link ; srcu-rscsi) & loc) |
  127. (rcu-rscsi ; rcu-link ; rcu-gp) |
  128. ((srcu-rscsi ; rcu-link ; srcu-gp) & loc) |
  129. (rcu-gp ; rcu-link ; rcu-order ; rcu-link ; rcu-rscsi) |
  130. ((srcu-gp ; rcu-link ; rcu-order ; rcu-link ; srcu-rscsi) & loc) |
  131. (rcu-rscsi ; rcu-link ; rcu-order ; rcu-link ; rcu-gp) |
  132. ((srcu-rscsi ; rcu-link ; rcu-order ; rcu-link ; srcu-gp) & loc) |
  133. (rcu-order ; rcu-link ; rcu-order)
  134. let rcu-fence = po ; rcu-order ; po?
  135. let fence = fence | rcu-fence
  136. let strong-fence = strong-fence | rcu-fence
  137. (* rb orders instructions just as pb does *)
  138. let rb = prop ; rcu-fence ; hb* ; pb* ; [Marked]
  139. irreflexive rb as rcu
  140. (*
  141. * The happens-before, propagation, and rcu constraints are all
  142. * expressions of temporal ordering. They could be replaced by
  143. * a single constraint on an "executes-before" relation, xb:
  144. *
  145. * let xb = hb | pb | rb
  146. * acyclic xb as executes-before
  147. *)
  148. (*********************************)
  149. (* Plain accesses and data races *)
  150. (*********************************)
  151. (* Warn about plain writes and marked accesses in the same region *)
  152. let mixed-accesses = ([Plain & W] ; (po-loc \ barrier) ; [Marked]) |
  153. ([Marked] ; (po-loc \ barrier) ; [Plain & W])
  154. flag ~empty mixed-accesses as mixed-accesses
  155. (* Executes-before and visibility *)
  156. let xbstar = (hb | pb | rb)*
  157. let vis = cumul-fence* ; rfe? ; [Marked] ;
  158. ((strong-fence ; [Marked] ; xbstar) | (xbstar & int))
  159. (* Boundaries for lifetimes of plain accesses *)
  160. let w-pre-bounded = [Marked] ; (addr | fence)?
  161. let r-pre-bounded = [Marked] ; (addr | nonrw-fence |
  162. ([R4rmb] ; fencerel(Rmb) ; [~Noreturn]))?
  163. let w-post-bounded = fence? ; [Marked] ; rmw-sequence
  164. let r-post-bounded = (nonrw-fence | ([~Noreturn] ; fencerel(Rmb) ; [R4rmb]))? ;
  165. [Marked]
  166. (* Visibility and executes-before for plain accesses *)
  167. let ww-vis = fence | (strong-fence ; xbstar ; w-pre-bounded) |
  168. (w-post-bounded ; vis ; w-pre-bounded)
  169. let wr-vis = fence | (strong-fence ; xbstar ; r-pre-bounded) |
  170. (w-post-bounded ; vis ; r-pre-bounded)
  171. let rw-xbstar = fence | (r-post-bounded ; xbstar ; w-pre-bounded)
  172. (* Potential races *)
  173. let pre-race = ext & ((Plain * M) | ((M \ IW) * Plain))
  174. (* Coherence requirements for plain accesses *)
  175. let wr-incoh = pre-race & rf & rw-xbstar^-1
  176. let rw-incoh = pre-race & fr & wr-vis^-1
  177. let ww-incoh = pre-race & co & ww-vis^-1
  178. empty (wr-incoh | rw-incoh | ww-incoh) as plain-coherence
  179. (* Actual races *)
  180. let ww-nonrace = ww-vis & ((Marked * W) | rw-xbstar) & ((W * Marked) | wr-vis)
  181. let ww-race = (pre-race & co) \ ww-nonrace
  182. let wr-race = (pre-race & (co? ; rf)) \ wr-vis \ rw-xbstar^-1
  183. let rw-race = (pre-race & fr) \ rw-xbstar
  184. flag ~empty (ww-race | wr-race | rw-race) as data-race