33use alloc:: boxed:: Box ;
44use alloc:: sync:: Arc ;
55use core:: cell:: UnsafeCell ;
6- use core:: fmt;
76use core:: ops:: { Deref , DerefMut } ;
87use core:: pin:: Pin ;
9- use core:: sync:: atomic:: AtomicUsize ;
8+ use core:: sync:: atomic:: AtomicPtr ;
109use core:: sync:: atomic:: Ordering :: SeqCst ;
10+ use core:: { fmt, ptr} ;
1111#[ cfg( feature = "bilock" ) ]
1212use futures_core:: future:: Future ;
1313use futures_core:: task:: { Context , Poll , Waker } ;
@@ -41,7 +41,7 @@ pub struct BiLock<T> {
4141
4242#[ derive( Debug ) ]
4343struct Inner < T > {
44- state : AtomicUsize ,
44+ state : AtomicPtr < Waker > ,
4545 value : Option < UnsafeCell < T > > ,
4646}
4747
@@ -61,7 +61,10 @@ impl<T> BiLock<T> {
6161 /// Similarly, reuniting the lock and extracting the inner value is only
6262 /// possible when `T` is `Unpin`.
6363 pub fn new ( t : T ) -> ( Self , Self ) {
64- let arc = Arc :: new ( Inner { state : AtomicUsize :: new ( 0 ) , value : Some ( UnsafeCell :: new ( t) ) } ) ;
64+ let arc = Arc :: new ( Inner {
65+ state : AtomicPtr :: new ( ptr:: null_mut ( ) ) ,
66+ value : Some ( UnsafeCell :: new ( t) ) ,
67+ } ) ;
6568
6669 ( Self { arc : arc. clone ( ) } , Self { arc } )
6770 }
@@ -87,7 +90,8 @@ impl<T> BiLock<T> {
8790 pub fn poll_lock ( & self , cx : & mut Context < ' _ > ) -> Poll < BiLockGuard < ' _ , T > > {
8891 let mut waker = None ;
8992 loop {
90- match self . arc . state . swap ( 1 , SeqCst ) {
93+ let n = self . arc . state . swap ( invalid_ptr ( 1 ) , SeqCst ) ;
94+ match n as usize {
9195 // Woohoo, we grabbed the lock!
9296 0 => return Poll :: Ready ( BiLockGuard { bilock : self } ) ,
9397
@@ -96,27 +100,27 @@ impl<T> BiLock<T> {
96100
97101 // A task was previously blocked on this lock, likely our task,
98102 // so we need to update that task.
99- n => unsafe {
100- let mut prev = Box :: from_raw ( n as * mut Waker ) ;
103+ _ => unsafe {
104+ let mut prev = Box :: from_raw ( n) ;
101105 * prev = cx. waker ( ) . clone ( ) ;
102106 waker = Some ( prev) ;
103107 } ,
104108 }
105109
106110 // type ascription for safety's sake!
107111 let me: Box < Waker > = waker. take ( ) . unwrap_or_else ( || Box :: new ( cx. waker ( ) . clone ( ) ) ) ;
108- let me = Box :: into_raw ( me) as usize ;
112+ let me = Box :: into_raw ( me) ;
109113
110- match self . arc . state . compare_exchange ( 1 , me, SeqCst , SeqCst ) {
114+ match self . arc . state . compare_exchange ( invalid_ptr ( 1 ) , me, SeqCst , SeqCst ) {
111115 // The lock is still locked, but we've now parked ourselves, so
112116 // just report that we're scheduled to receive a notification.
113117 Ok ( _) => return Poll :: Pending ,
114118
115119 // Oops, looks like the lock was unlocked after our swap above
116120 // and before the compare_exchange. Deallocate what we just
117121 // allocated and go through the loop again.
118- Err ( 0 ) => unsafe {
119- waker = Some ( Box :: from_raw ( me as * mut Waker ) ) ;
122+ Err ( n ) if n . is_null ( ) => unsafe {
123+ waker = Some ( Box :: from_raw ( me) ) ;
120124 } ,
121125
122126 // The top of this loop set the previous state to 1, so if we
@@ -125,7 +129,7 @@ impl<T> BiLock<T> {
125129 // but we're trying to acquire the lock and there's only one
126130 // other reference of the lock, so it should be impossible for
127131 // that task to ever block itself.
128- Err ( n) => panic ! ( "invalid state: {}" , n) ,
132+ Err ( n) => panic ! ( "invalid state: {}" , n as usize ) ,
129133 }
130134 }
131135 }
@@ -164,7 +168,8 @@ impl<T> BiLock<T> {
164168 }
165169
166170 fn unlock ( & self ) {
167- match self . arc . state . swap ( 0 , SeqCst ) {
171+ let n = self . arc . state . swap ( ptr:: null_mut ( ) , SeqCst ) ;
172+ match n as usize {
168173 // we've locked the lock, shouldn't be possible for us to see an
169174 // unlocked lock.
170175 0 => panic ! ( "invalid unlocked state" ) ,
@@ -174,8 +179,8 @@ impl<T> BiLock<T> {
174179
175180 // Another task has parked themselves on this lock, let's wake them
176181 // up as its now their turn.
177- n => unsafe {
178- Box :: from_raw ( n as * mut Waker ) . wake ( ) ;
182+ _ => unsafe {
183+ Box :: from_raw ( n) . wake ( ) ;
179184 } ,
180185 }
181186 }
@@ -189,7 +194,7 @@ impl<T: Unpin> Inner<T> {
189194
190195impl < T > Drop for Inner < T > {
191196 fn drop ( & mut self ) {
192- assert_eq ! ( self . state. load( SeqCst ) , 0 ) ;
197+ assert ! ( self . state. load( SeqCst ) . is_null ( ) ) ;
193198 }
194199}
195200
@@ -277,3 +282,12 @@ impl<'a, T> Future for BiLockAcquire<'a, T> {
277282 self . bilock . poll_lock ( cx)
278283 }
279284}
285+
286+ // Based on core::ptr::invalid_mut. Equivalent to `addr as *mut T`, but is strict-provenance compatible.
287+ #[ allow( clippy:: useless_transmute) ]
288+ #[ inline]
289+ fn invalid_ptr < T > ( addr : usize ) -> * mut T {
290+ // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
291+ // pointer).
292+ unsafe { core:: mem:: transmute ( addr) }
293+ }
0 commit comments