lock.cat 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: GPL-2.0+
  2. (*
  3. * Copyright (C) 2016 Luc Maranget <[email protected]> for Inria
  4. * Copyright (C) 2017 Alan Stern <[email protected]>
  5. *)
  6. (*
  7. * Generate coherence orders and handle lock operations
  8. *)
  9. include "cross.cat"
  10. (*
  11. * The lock-related events generated by herd7 are as follows:
  12. *
  13. * LKR Lock-Read: the read part of a spin_lock() or successful
  14. * spin_trylock() read-modify-write event pair
  15. * LKW Lock-Write: the write part of a spin_lock() or successful
  16. * spin_trylock() RMW event pair
  17. * UL Unlock: a spin_unlock() event
  18. * LF Lock-Fail: a failed spin_trylock() event
  19. * RL Read-Locked: a spin_is_locked() event which returns True
  20. * RU Read-Unlocked: a spin_is_locked() event which returns False
  21. *
  22. * LKR and LKW events always come paired, like all RMW event sequences.
  23. *
  24. * LKR, LF, RL, and RU are read events; LKR has Acquire ordering.
  25. * LKW and UL are write events; UL has Release ordering.
  26. * LKW, LF, RL, and RU have no ordering properties.
  27. *)
  28. (* Backward compatibility *)
  29. let RL = try RL with emptyset
  30. let RU = try RU with emptyset
  31. (* Treat RL as a kind of LF: a read with no ordering properties *)
  32. let LF = LF | RL
  33. (* There should be no ordinary R or W accesses to spinlocks *)
  34. let ALL-LOCKS = LKR | LKW | UL | LF | RU
  35. flag ~empty [M \ IW] ; loc ; [ALL-LOCKS] as mixed-lock-accesses
  36. (* Link Lock-Reads to their RMW-partner Lock-Writes *)
  37. let lk-rmw = ([LKR] ; po-loc ; [LKW]) \ (po ; po)
  38. let rmw = rmw | lk-rmw
  39. (* The litmus test is invalid if an LKR/LKW event is not part of an RMW pair *)
  40. flag ~empty LKW \ range(lk-rmw) as unpaired-LKW
  41. flag ~empty LKR \ domain(lk-rmw) as unpaired-LKR
  42. (*
  43. * An LKR must always see an unlocked value; spin_lock() calls nested
  44. * inside a critical section (for the same lock) always deadlock.
  45. *)
  46. empty ([LKW] ; po-loc ; [LKR]) \ (po-loc ; [UL] ; po-loc) as lock-nest
  47. (* The final value of a spinlock should not be tested *)
  48. flag ~empty [FW] ; loc ; [ALL-LOCKS] as lock-final
  49. (*
  50. * Put lock operations in their appropriate classes, but leave UL out of W
  51. * until after the co relation has been generated.
  52. *)
  53. let R = R | LKR | LF | RU
  54. let W = W | LKW
  55. let Release = Release | UL
  56. let Acquire = Acquire | LKR
  57. (* Match LKW events to their corresponding UL events *)
  58. let critical = ([LKW] ; po-loc ; [UL]) \ (po-loc ; [LKW | UL] ; po-loc)
  59. flag ~empty UL \ range(critical) as unmatched-unlock
  60. (* Allow up to one unmatched LKW per location; more must deadlock *)
  61. let UNMATCHED-LKW = LKW \ domain(critical)
  62. empty ([UNMATCHED-LKW] ; loc ; [UNMATCHED-LKW]) \ id as unmatched-locks
  63. (* rfi for LF events: link each LKW to the LF events in its critical section *)
  64. let rfi-lf = ([LKW] ; po-loc ; [LF]) \ ([LKW] ; po-loc ; [UL] ; po-loc)
  65. (* rfe for LF events *)
  66. let all-possible-rfe-lf =
  67. (*
  68. * Given an LF event r, compute the possible rfe edges for that event
  69. * (all those starting from LKW events in other threads),
  70. * and then convert that relation to a set of single-edge relations.
  71. *)
  72. let possible-rfe-lf r =
  73. let pair-to-relation p = p ++ 0
  74. in map pair-to-relation ((LKW * {r}) & loc & ext)
  75. (* Do this for each LF event r that isn't in rfi-lf *)
  76. in map possible-rfe-lf (LF \ range(rfi-lf))
  77. (* Generate all rf relations for LF events *)
  78. with rfe-lf from cross(all-possible-rfe-lf)
  79. let rf-lf = rfe-lf | rfi-lf
  80. (*
  81. * RU, i.e., spin_is_locked() returning False, is slightly different.
  82. * We rely on the memory model to rule out cases where spin_is_locked()
  83. * within one of the lock's critical sections returns False.
  84. *)
  85. (* rfi for RU events: an RU may read from the last po-previous UL *)
  86. let rfi-ru = ([UL] ; po-loc ; [RU]) \ ([UL] ; po-loc ; [LKW] ; po-loc)
  87. (* rfe for RU events: an RU may read from an external UL or the initial write *)
  88. let all-possible-rfe-ru =
  89. let possible-rfe-ru r =
  90. let pair-to-relation p = p ++ 0
  91. in map pair-to-relation (((UL | IW) * {r}) & loc & ext)
  92. in map possible-rfe-ru RU
  93. (* Generate all rf relations for RU events *)
  94. with rfe-ru from cross(all-possible-rfe-ru)
  95. let rf-ru = rfe-ru | rfi-ru
  96. (* Final rf relation *)
  97. let rf = rf | rf-lf | rf-ru
  98. (* Generate all co relations, including LKW events but not UL *)
  99. let co0 = co0 | ([IW] ; loc ; [LKW]) |
  100. (([LKW] ; loc ; [UNMATCHED-LKW]) \ [UNMATCHED-LKW])
  101. include "cos-opt.cat"
  102. let W = W | UL
  103. let M = R | W
  104. (* Merge UL events into co *)
  105. let co = (co | critical | (critical^-1 ; co))+
  106. let coe = co & ext
  107. let coi = co & int
  108. (* Merge LKR events into rf *)
  109. let rf = rf | ([IW | UL] ; singlestep(co) ; lk-rmw^-1)
  110. let rfe = rf & ext
  111. let rfi = rf & int
  112. let fr = rf^-1 ; co
  113. let fre = fr & ext
  114. let fri = fr & int
  115. show co,rf,fr