locked_by.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // SPDX-License-Identifier: GPL-2.0
  2. //! A wrapper for data protected by a lock that does not wrap it.
  3. use super::{lock::Backend, lock::Lock};
  4. use crate::build_assert;
  5. use core::{cell::UnsafeCell, mem::size_of, ptr};
  6. /// Allows access to some data to be serialised by a lock that does not wrap it.
  7. ///
  8. /// In most cases, data protected by a lock is wrapped by the appropriate lock type, e.g.,
  9. /// [`Mutex`] or [`SpinLock`]. [`LockedBy`] is meant for cases when this is not possible.
  10. /// For example, if a container has a lock and some data in the contained elements needs
  11. /// to be protected by the same lock.
  12. ///
  13. /// [`LockedBy`] wraps the data in lieu of another locking primitive, and only allows access to it
  14. /// when the caller shows evidence that the 'external' lock is locked. It panics if the evidence
  15. /// refers to the wrong instance of the lock.
  16. ///
  17. /// [`Mutex`]: super::Mutex
  18. /// [`SpinLock`]: super::SpinLock
  19. ///
  20. /// # Examples
  21. ///
  22. /// The following is an example for illustrative purposes: `InnerDirectory::bytes_used` is an
  23. /// aggregate of all `InnerFile::bytes_used` and must be kept consistent; so we wrap `InnerFile` in
  24. /// a `LockedBy` so that it shares a lock with `InnerDirectory`. This allows us to enforce at
  25. /// compile-time that access to `InnerFile` is only granted when an `InnerDirectory` is also
  26. /// locked; we enforce at run time that the right `InnerDirectory` is locked.
  27. ///
  28. /// ```
  29. /// use kernel::sync::{LockedBy, Mutex};
  30. ///
  31. /// struct InnerFile {
  32. /// bytes_used: u64,
  33. /// }
  34. ///
  35. /// struct File {
  36. /// _ino: u32,
  37. /// inner: LockedBy<InnerFile, InnerDirectory>,
  38. /// }
  39. ///
  40. /// struct InnerDirectory {
  41. /// /// The sum of the bytes used by all files.
  42. /// bytes_used: u64,
  43. /// _files: KVec<File>,
  44. /// }
  45. ///
  46. /// struct Directory {
  47. /// _ino: u32,
  48. /// inner: Mutex<InnerDirectory>,
  49. /// }
  50. ///
  51. /// /// Prints `bytes_used` from both the directory and file.
  52. /// fn print_bytes_used(dir: &Directory, file: &File) {
  53. /// let guard = dir.inner.lock();
  54. /// let inner_file = file.inner.access(&guard);
  55. /// pr_info!("{} {}", guard.bytes_used, inner_file.bytes_used);
  56. /// }
  57. ///
  58. /// /// Increments `bytes_used` for both the directory and file.
  59. /// fn inc_bytes_used(dir: &Directory, file: &File) {
  60. /// let mut guard = dir.inner.lock();
  61. /// guard.bytes_used += 10;
  62. ///
  63. /// let file_inner = file.inner.access_mut(&mut guard);
  64. /// file_inner.bytes_used += 10;
  65. /// }
  66. ///
  67. /// /// Creates a new file.
  68. /// fn new_file(ino: u32, dir: &Directory) -> File {
  69. /// File {
  70. /// _ino: ino,
  71. /// inner: LockedBy::new(&dir.inner, InnerFile { bytes_used: 0 }),
  72. /// }
  73. /// }
  74. /// ```
  75. pub struct LockedBy<T: ?Sized, U: ?Sized> {
  76. owner: *const U,
  77. data: UnsafeCell<T>,
  78. }
  79. // SAFETY: `LockedBy` can be transferred across thread boundaries iff the data it protects can.
  80. unsafe impl<T: ?Sized + Send, U: ?Sized> Send for LockedBy<T, U> {}
  81. // SAFETY: If `T` is not `Sync`, then parallel shared access to this `LockedBy` allows you to use
  82. // `access_mut` to hand out `&mut T` on one thread at the time. The requirement that `T: Send` is
  83. // sufficient to allow that.
  84. //
  85. // If `T` is `Sync`, then the `access` method also becomes available, which allows you to obtain
  86. // several `&T` from several threads at once. However, this is okay as `T` is `Sync`.
  87. unsafe impl<T: ?Sized + Send, U: ?Sized> Sync for LockedBy<T, U> {}
  88. impl<T, U> LockedBy<T, U> {
  89. /// Constructs a new instance of [`LockedBy`].
  90. ///
  91. /// It stores a raw pointer to the owner that is never dereferenced. It is only used to ensure
  92. /// that the right owner is being used to access the protected data. If the owner is freed, the
  93. /// data becomes inaccessible; if another instance of the owner is allocated *on the same
  94. /// memory location*, the data becomes accessible again: none of this affects memory safety
  95. /// because in any case at most one thread (or CPU) can access the protected data at a time.
  96. pub fn new<B: Backend>(owner: &Lock<U, B>, data: T) -> Self {
  97. build_assert!(
  98. size_of::<Lock<U, B>>() > 0,
  99. "The lock type cannot be a ZST because it may be impossible to distinguish instances"
  100. );
  101. Self {
  102. owner: owner.data.get(),
  103. data: UnsafeCell::new(data),
  104. }
  105. }
  106. }
  107. impl<T: ?Sized, U> LockedBy<T, U> {
  108. /// Returns a reference to the protected data when the caller provides evidence (via a
  109. /// reference) that the owner is locked.
  110. ///
  111. /// `U` cannot be a zero-sized type (ZST) because there are ways to get an `&U` that matches
  112. /// the data protected by the lock without actually holding it.
  113. ///
  114. /// # Panics
  115. ///
  116. /// Panics if `owner` is different from the data protected by the lock used in
  117. /// [`new`](LockedBy::new).
  118. pub fn access<'a>(&'a self, owner: &'a U) -> &'a T
  119. where
  120. T: Sync,
  121. {
  122. build_assert!(
  123. size_of::<U>() > 0,
  124. "`U` cannot be a ZST because `owner` wouldn't be unique"
  125. );
  126. if !ptr::eq(owner, self.owner) {
  127. panic!("mismatched owners");
  128. }
  129. // SAFETY: `owner` is evidence that there are only shared references to the owner for the
  130. // duration of 'a, so it's not possible to use `Self::access_mut` to obtain a mutable
  131. // reference to the inner value that aliases with this shared reference. The type is `Sync`
  132. // so there are no other requirements.
  133. unsafe { &*self.data.get() }
  134. }
  135. /// Returns a mutable reference to the protected data when the caller provides evidence (via a
  136. /// mutable owner) that the owner is locked mutably.
  137. ///
  138. /// `U` cannot be a zero-sized type (ZST) because there are ways to get an `&mut U` that
  139. /// matches the data protected by the lock without actually holding it.
  140. ///
  141. /// Showing a mutable reference to the owner is sufficient because we know no other references
  142. /// can exist to it.
  143. ///
  144. /// # Panics
  145. ///
  146. /// Panics if `owner` is different from the data protected by the lock used in
  147. /// [`new`](LockedBy::new).
  148. pub fn access_mut<'a>(&'a self, owner: &'a mut U) -> &'a mut T {
  149. build_assert!(
  150. size_of::<U>() > 0,
  151. "`U` cannot be a ZST because `owner` wouldn't be unique"
  152. );
  153. if !ptr::eq(owner, self.owner) {
  154. panic!("mismatched owners");
  155. }
  156. // SAFETY: `owner` is evidence that there is only one reference to the owner.
  157. unsafe { &mut *self.data.get() }
  158. }
  159. }