util.rs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. //! useful structures
  2. use core::{
  3. arch::asm,
  4. cell::UnsafeCell,
  5. marker::PhantomData,
  6. mem::MaybeUninit,
  7. ops::{Deref, DerefMut},
  8. ptr::Pointee,
  9. };
  10. /// Use only amo instructions on mutex; no lr/sc instruction is used
  11. pub struct AmoMutex<T: ?Sized> {
  12. lock: UnsafeCell<u32>,
  13. data: UnsafeCell<T>,
  14. }
  15. pub struct AmoMutexGuard<'a, T: ?Sized> {
  16. lock: *mut u32,
  17. data: &'a mut T,
  18. }
  19. impl<T> AmoMutex<T> {
  20. /// Create a new AmoMutex
  21. #[inline]
  22. pub const fn new(data: T) -> Self {
  23. Self {
  24. lock: UnsafeCell::new(0),
  25. data: UnsafeCell::new(data),
  26. }
  27. }
  28. /// Locks the mutex and returns a guard that permits access to the inner data.
  29. #[inline]
  30. pub fn lock(&self) -> AmoMutexGuard<T> {
  31. let lock = self.lock.get();
  32. unsafe {
  33. asm!(
  34. "1: lw {tmp}, ({lock})", // check if lock is held
  35. " bnez {tmp}, 1b", // retry if held
  36. " amoswap.w.aq {tmp}, {one}, ({lock})", // attempt to acquire lock
  37. " bnez {tmp}, 1b", // retry if held
  38. tmp = out(reg) _,
  39. lock = in(reg) lock,
  40. one = in(reg) 1,
  41. options(nostack)
  42. );
  43. }
  44. AmoMutexGuard {
  45. lock,
  46. data: unsafe { &mut *self.data.get() },
  47. }
  48. }
  49. }
  50. unsafe impl<T: ?Sized + Send> Sync for AmoMutex<T> {}
  51. unsafe impl<T: ?Sized + Send> Send for AmoMutex<T> {}
  52. impl<'a, T: ?Sized> Deref for AmoMutexGuard<'a, T> {
  53. type Target = T;
  54. #[inline]
  55. fn deref(&self) -> &T {
  56. self.data
  57. }
  58. }
  59. impl<'a, T: ?Sized> DerefMut for AmoMutexGuard<'a, T> {
  60. #[inline]
  61. fn deref_mut(&mut self) -> &mut T {
  62. self.data
  63. }
  64. }
  65. impl<'a, T: ?Sized> Drop for AmoMutexGuard<'a, T> {
  66. /// The dropping of the mutex guard will release the lock it was created from.
  67. #[inline]
  68. fn drop(&mut self) {
  69. unsafe {
  70. asm!(
  71. "amoswap.w.rl zero, zero, ({lock})", // release lock by storing 0
  72. lock = in(reg) self.lock,
  73. );
  74. }
  75. }
  76. }
  77. /// 只使用 AMO 指令的一次初始化引用存储。
  78. pub struct AmoOnceRef<'a, T: ?Sized> {
  79. /// As atomic bool, to check if it is the first time to set `ptr`.
  80. lock: UnsafeCell<u32>,
  81. ptr: UnsafeCell<*const ()>,
  82. meta: UnsafeCell<MaybeUninit<<T as Pointee>::Metadata>>,
  83. _lifetime: PhantomData<&'a ()>,
  84. }
  85. /// 如果 AmoOncePtr 保存的引用是静态的,自然可以随意移动。
  86. unsafe impl<T: ?Sized> Send for AmoOnceRef<'static, T> {}
  87. /// AmoOncePtr 不提供锁。
  88. unsafe impl<T: ?Sized + Sync> Sync for AmoOnceRef<'static, T> {}
  89. impl<'a, T: ?Sized> AmoOnceRef<'a, T> {
  90. #[inline]
  91. pub const fn new() -> Self {
  92. Self {
  93. lock: UnsafeCell::new(0),
  94. ptr: UnsafeCell::new(core::ptr::null()),
  95. meta: UnsafeCell::new(MaybeUninit::uninit()),
  96. _lifetime: PhantomData,
  97. }
  98. }
  99. pub fn try_call_once(&self, r#ref: &'a T) -> bool {
  100. let ptr = r#ref as *const T;
  101. let locked: u32;
  102. unsafe {
  103. asm!(
  104. "
  105. lw {locked}, ({lock})
  106. bnez {locked}, 1f
  107. amoswap.w.aq {locked}, {one}, ({lock})
  108. 1: ",
  109. lock = in(reg) self.lock.get(),
  110. one = in(reg) 1,
  111. locked = out(reg) locked,
  112. );
  113. }
  114. if locked == 0 {
  115. // 取得锁,初始化对象
  116. unsafe {
  117. // amo rl 保证先初始化 meta 后设置指针
  118. (*self.meta.get()) = MaybeUninit::new(core::ptr::metadata(ptr));
  119. #[cfg(target_pointer_width = "32")]
  120. asm!(
  121. "amoswap.w.rl zero, {src}, ({dst})",
  122. src = in(reg) ptr as *const (),
  123. dst = in(reg) self.ptr.get(),
  124. );
  125. #[cfg(target_pointer_width = "64")]
  126. asm!(
  127. "amoswap.d.rl zero, {src}, ({dst})",
  128. src = in(reg) ptr as *const (),
  129. dst = in(reg) self.ptr.get(),
  130. );
  131. }
  132. true
  133. } else {
  134. // 未取得锁,对象已被初始化过
  135. false
  136. }
  137. }
  138. #[allow(unused)]
  139. pub fn call_once(&self, r#ref: &'static T) -> Result<&T, &T> {
  140. if self.try_call_once(r#ref) {
  141. Ok(r#ref)
  142. } else {
  143. Err(self.wait())
  144. }
  145. }
  146. pub fn wait(&self) -> &T {
  147. loop {
  148. // 反复读直到非空。
  149. let ptr = unsafe { *self.ptr.get() };
  150. if !ptr.is_null() {
  151. return unsafe { self.build_ref_unchecked(ptr) };
  152. }
  153. }
  154. }
  155. pub fn get(&self) -> Option<&T> {
  156. let ptr: *const ();
  157. unsafe {
  158. // 先获取指针。如果指针非空,元数据一定存在。
  159. // FIXME AMO 设的值是否一定对 LD 可见?如果确定就不需要 AMO 读了。
  160. #[cfg(target_pointer_width = "32")]
  161. asm!(" lw {dst}, ({src})
  162. bnez {dst}, 1f
  163. amoadd.w.aq {dst}, zero, ({src})
  164. 1: ",
  165. src = in(reg) self.ptr.get(),
  166. dst = out(reg) ptr,
  167. );
  168. #[cfg(target_pointer_width = "64")]
  169. asm!(" ld {dst}, ({src})
  170. bnez {dst}, 1f
  171. amoadd.d.aq {dst}, zero, ({src})
  172. 1: ",
  173. src = in(reg) self.ptr.get(),
  174. dst = out(reg) ptr,
  175. );
  176. }
  177. if !ptr.is_null() {
  178. Some(unsafe { self.build_ref_unchecked(ptr) })
  179. } else {
  180. None
  181. }
  182. }
  183. /// 利用指针和元数据生成引用。需要保证传入的指针非空。如果能传入非空指针,meta 也一定存在。
  184. #[inline]
  185. unsafe fn build_ref_unchecked(&self, ptr: *const ()) -> &T {
  186. &*core::ptr::from_raw_parts(ptr, (*self.meta.get()).assume_init())
  187. }
  188. }
  189. /// 分解一个胖指针,使之 Sized。
  190. pub struct NullableMut<'a, T: ?Sized> {
  191. ptr: *mut (),
  192. meta: MaybeUninit<<T as Pointee>::Metadata>,
  193. _lifetime: PhantomData<&'a ()>,
  194. }
  195. impl<'a, T: ?Sized> NullableMut<'a, T> {
  196. pub const fn new() -> Self {
  197. Self {
  198. ptr: core::ptr::null_mut(),
  199. meta: MaybeUninit::uninit(),
  200. _lifetime: PhantomData,
  201. }
  202. }
  203. pub fn set(&mut self, r#ref: &'a mut T) {
  204. let ptr = r#ref as *mut T;
  205. self.ptr = ptr.cast();
  206. self.meta = MaybeUninit::new(core::ptr::metadata(ptr));
  207. }
  208. pub fn get(&mut self) -> Option<&mut T> {
  209. if !self.ptr.is_null() {
  210. Some(unsafe { &mut *core::ptr::from_raw_parts_mut(self.ptr, self.meta.assume_init()) })
  211. } else {
  212. None
  213. }
  214. }
  215. }
  216. /// 如果 AmoOncePtr 保存的引用是静态的,自然可以随意移动。
  217. unsafe impl<T: ?Sized> Send for NullableMut<'static, T> {}
  218. /// AmoOncePtr 不提供锁。
  219. unsafe impl<T: ?Sized + Sync> Sync for NullableMut<'static, T> {}