]> git.proxmox.com Git - rustc.git/blob - vendor/parking_lot-0.9.0/src/elision.rs
New upstream version 1.43.0+dfsg1
[rustc.git] / vendor / parking_lot-0.9.0 / src / elision.rs
1 // Copyright 2016 Amanieu d'Antras
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7
8 use std::sync::atomic::AtomicUsize;
9
10 // Extension trait to add lock elision primitives to atomic types
11 pub trait AtomicElisionExt {
12 type IntType;
13
14 // Perform a compare_exchange and start a transaction
15 fn elision_compare_exchange_acquire(
16 &self,
17 current: Self::IntType,
18 new: Self::IntType,
19 ) -> Result<Self::IntType, Self::IntType>;
20
21 // Perform a fetch_sub and end a transaction
22 fn elision_fetch_sub_release(&self, val: Self::IntType) -> Self::IntType;
23 }
24
25 // Indicates whether the target architecture supports lock elision
26 #[inline]
27 pub fn have_elision() -> bool {
28 cfg!(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64"),))
29 }
30
31 // This implementation is never actually called because it is guarded by
32 // have_elision().
33 #[cfg(not(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64"))))]
34 impl AtomicElisionExt for AtomicUsize {
35 type IntType = usize;
36
37 #[inline]
38 fn elision_compare_exchange_acquire(&self, _: usize, _: usize) -> Result<usize, usize> {
39 unreachable!();
40 }
41
42 #[inline]
43 fn elision_fetch_sub_release(&self, _: usize) -> usize {
44 unreachable!();
45 }
46 }
47
48 #[cfg(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64")))]
49 impl AtomicElisionExt for AtomicUsize {
50 type IntType = usize;
51
52 #[cfg(target_pointer_width = "32")]
53 #[inline]
54 fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result<usize, usize> {
55 unsafe {
56 let prev: usize;
57 asm!("xacquire; lock; cmpxchgl $2, $1"
58 : "={eax}" (prev), "+*m" (self)
59 : "r" (new), "{eax}" (current)
60 : "memory"
61 : "volatile");
62 if prev == current { Ok(prev) } else { Err(prev) }
63 }
64 }
65 #[cfg(target_pointer_width = "64")]
66 #[inline]
67 fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result<usize, usize> {
68 unsafe {
69 let prev: usize;
70 asm!("xacquire; lock; cmpxchgq $2, $1"
71 : "={rax}" (prev), "+*m" (self)
72 : "r" (new), "{rax}" (current)
73 : "memory"
74 : "volatile");
75 if prev == current { Ok(prev) } else { Err(prev) }
76 }
77 }
78
79 #[cfg(target_pointer_width = "32")]
80 #[inline]
81 fn elision_fetch_sub_release(&self, val: usize) -> usize {
82 unsafe {
83 let prev: usize;
84 asm!("xrelease; lock; xaddl $2, $1"
85 : "=r" (prev), "+*m" (self)
86 : "0" (val.wrapping_neg())
87 : "memory"
88 : "volatile");
89 prev
90 }
91 }
92 #[cfg(target_pointer_width = "64")]
93 #[inline]
94 fn elision_fetch_sub_release(&self, val: usize) -> usize {
95 unsafe {
96 let prev: usize;
97 asm!("xrelease; lock; xaddq $2, $1"
98 : "=r" (prev), "+*m" (self)
99 : "0" (val.wrapping_neg())
100 : "memory"
101 : "volatile");
102 prev
103 }
104 }
105 }