]> git.proxmox.com Git - cargo.git/blob - vendor/crossbeam-0.2.12/src/mem/cache_padded.rs
New upstream version 0.24.0
[cargo.git] / vendor / crossbeam-0.2.12 / src / mem / cache_padded.rs
1 use std::marker;
2 use std::cell::UnsafeCell;
3 use std::fmt;
4 use std::mem;
5 use std::ptr;
6 use std::ops::{Deref, DerefMut};
7
8 // For now, treat this as an arch-independent constant.
9 const CACHE_LINE: usize = 32;
10
11 #[cfg_attr(feature = "nightly",
12 repr(simd))]
13 #[derive(Debug)]
14 struct Padding(u64, u64, u64, u64);
15
16 /// Pad `T` to the length of a cacheline.
17 ///
18 /// Sometimes concurrent programming requires a piece of data to be padded out
19 /// to the size of a cacheline to avoid "false sharing": cachelines being
20 /// invalidated due to unrelated concurrent activity. Use the `CachePadded` type
21 /// when you want to *avoid* cache locality.
22 ///
23 /// At the moment, cache lines are assumed to be 32 * sizeof(usize) on all
24 /// architectures.
25 ///
26 /// **Warning**: the wrapped data is never dropped; move out using `ptr::read`
27 /// if you need to run dtors.
28 pub struct CachePadded<T> {
29 data: UnsafeCell<[usize; CACHE_LINE]>,
30 _marker: ([Padding; 0], marker::PhantomData<T>),
31 }
32
33 impl<T> fmt::Debug for CachePadded<T> {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 write!(f, "CachePadded {{ ... }}")
36 }
37 }
38
39 unsafe impl<T: Send> Send for CachePadded<T> {}
40 unsafe impl<T: Sync> Sync for CachePadded<T> {}
41
42 #[cfg(not(feature = "nightly"))]
43 macro_rules! declare_zeros_valid {
44 () => {
45 /// Types for which mem::zeroed() is safe.
46 ///
47 /// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be
48 /// a valid member of the type `T`.
49 pub unsafe trait ZerosValid {}
50 }
51 }
52
53 #[cfg(feature = "nightly")]
54 macro_rules! declare_zeros_valid {
55 () => {
56 /// Types for which mem::zeroed() is safe.
57 ///
58 /// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be
59 /// a valid member of the type `T`.
60 pub unsafe auto trait ZerosValid {}
61 }
62 }
63
64 declare_zeros_valid!();
65
66 macro_rules! zeros_valid { ($( $T:ty )*) => ($(
67 unsafe impl ZerosValid for $T {}
68 )*)}
69
70 zeros_valid!(u8 u16 u32 u64 usize);
71 zeros_valid!(i8 i16 i32 i64 isize);
72
73 unsafe impl ZerosValid for ::std::sync::atomic::AtomicUsize {}
74 unsafe impl<T> ZerosValid for ::std::sync::atomic::AtomicPtr<T> {}
75
76 impl<T: ZerosValid> CachePadded<T> {
77 /// A const fn equivalent to mem::zeroed().
78 #[cfg(not(feature = "nightly"))]
79 pub fn zeroed() -> CachePadded<T> {
80 CachePadded {
81 data: UnsafeCell::new(([0; CACHE_LINE])),
82 _marker: ([], marker::PhantomData),
83 }
84 }
85
86 /// A const fn equivalent to mem::zeroed().
87 #[cfg(feature = "nightly")]
88 pub const fn zeroed() -> CachePadded<T> {
89 CachePadded {
90 data: UnsafeCell::new(([0; CACHE_LINE])),
91 _marker: ([], marker::PhantomData),
92 }
93 }
94 }
95
96 #[inline]
97 /// Assert that the size and alignment of `T` are consistent with `CachePadded<T>`.
98 fn assert_valid<T>() {
99 assert!(mem::size_of::<T>() <= mem::size_of::<CachePadded<T>>());
100 assert!(mem::align_of::<T>() <= mem::align_of::<CachePadded<T>>());
101 }
102
103 impl<T> CachePadded<T> {
104 /// Wrap `t` with cacheline padding.
105 ///
106 /// **Warning**: the wrapped data is never dropped; move out using
107 /// `ptr:read` if you need to run dtors.
108 pub fn new(t: T) -> CachePadded<T> {
109 assert_valid::<T>();
110 let ret = CachePadded {
111 data: UnsafeCell::new(([0; CACHE_LINE])),
112 _marker: ([], marker::PhantomData),
113 };
114 unsafe {
115 let p: *mut T = mem::transmute(&ret.data);
116 ptr::write(p, t);
117 }
118 ret
119 }
120 }
121
122 impl<T> Deref for CachePadded<T> {
123 type Target = T;
124 fn deref(&self) -> &T {
125 assert_valid::<T>();
126 unsafe { mem::transmute(&self.data) }
127 }
128 }
129
130 impl<T> DerefMut for CachePadded<T> {
131 fn deref_mut(&mut self) -> &mut T {
132 assert_valid::<T>();
133 unsafe { mem::transmute(&mut self.data) }
134 }
135 }
136
137 // FIXME: support Drop by pulling out a version usable for statics
138 /*
139 impl<T> Drop for CachePadded<T> {
140 fn drop(&mut self) {
141 assert_valid::<T>();
142 let p: *mut T = mem::transmute(&self.data);
143 mem::drop(ptr::read(p));
144 }
145 }
146 */
147
148 #[cfg(test)]
149 mod test {
150 use super::*;
151
152 #[test]
153 fn cache_padded_store_u64() {
154 let x: CachePadded<u64> = CachePadded::new(17);
155 assert_eq!(*x, 17);
156 }
157
158 #[test]
159 fn cache_padded_store_pair() {
160 let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37));
161 assert_eq!(x.0, 17);
162 assert_eq!(x.1, 37);
163 }
164 }