11//! Public API facades for the implementation details of [`Zalsa`] and [`ZalsaLocal`].
22use std:: marker:: PhantomData ;
3+ use std:: mem;
34use std:: panic:: RefUnwindSafe ;
45
56use crate :: database:: RawDatabase ;
@@ -25,8 +26,6 @@ pub struct StorageHandle<Db> {
2526
2627impl < Db > Clone for StorageHandle < Db > {
2728 fn clone ( & self ) -> Self {
28- * self . coordinate . clones . lock ( ) += 1 ;
29-
3029 Self {
3130 zalsa_impl : self . zalsa_impl . clone ( ) ,
3231 coordinate : CoordinateDrop ( Arc :: clone ( & self . coordinate ) ) ,
@@ -53,7 +52,7 @@ impl<Db: Database> StorageHandle<Db> {
5352 Self {
5453 zalsa_impl : Arc :: new ( Zalsa :: new :: < Db > ( event_callback, jars) ) ,
5554 coordinate : CoordinateDrop ( Arc :: new ( Coordinate {
56- clones : Mutex :: new ( 1 ) ,
55+ coordinate_lock : Mutex :: default ( ) ,
5756 cvar : Default :: default ( ) ,
5857 } ) ) ,
5958 phantom : PhantomData ,
@@ -95,17 +94,6 @@ impl<Db> Drop for Storage<Db> {
9594 }
9695}
9796
98- struct Coordinate {
99- /// Counter of the number of clones of actor. Begins at 1.
100- /// Incremented when cloned, decremented when dropped.
101- clones : Mutex < usize > ,
102- cvar : Condvar ,
103- }
104-
105- // We cannot panic while holding a lock to `clones: Mutex<usize>` and therefore we cannot enter an
106- // inconsistent state.
107- impl RefUnwindSafe for Coordinate { }
108-
10997impl < Db : Database > Default for Storage < Db > {
11098 fn default ( ) -> Self {
11199 Self :: new ( None )
@@ -168,12 +156,14 @@ impl<Db: Database> Storage<Db> {
168156 . zalsa_impl
169157 . event ( & || Event :: new ( EventKind :: DidSetCancellationFlag ) ) ;
170158
171- let mut clones = self . handle . coordinate . clones . lock ( ) ;
172- while * clones != 1 {
173- clones = self . handle . coordinate . cvar . wait ( clones) ;
174- }
175- // The ref count on the `Arc` should now be 1
176- let zalsa = Arc :: get_mut ( & mut self . handle . zalsa_impl ) . unwrap ( ) ;
159+ let mut coordinate_lock = self . handle . coordinate . coordinate_lock . lock ( ) ;
160+ let zalsa = loop {
161+ if let Some ( zalsa) = Arc :: get_mut ( & mut self . handle . zalsa_impl ) {
162+ // SAFETY: Polonius when ... https://github.com/rust-lang/rfcs/blob/master/text/2094-nll.md#problem-case-3-conditional-control-flow-across-functions
163+ break unsafe { mem:: transmute :: < & mut Zalsa , & mut Zalsa > ( zalsa) } ;
164+ }
165+ coordinate_lock = self . handle . coordinate . cvar . wait ( coordinate_lock) ;
166+ } ;
177167 // cancellation is done, so reset the flag
178168 zalsa. runtime_mut ( ) . reset_cancellation_flag ( ) ;
179169 zalsa
@@ -260,6 +250,16 @@ impl<Db: Database> Clone for Storage<Db> {
260250 }
261251}
262252
253+ /// A simplified `WaitGroup`, this is used together with `Arc<Zalsa>` as the actual counter
254+ struct Coordinate {
255+ coordinate_lock : Mutex < ( ) > ,
256+ cvar : Condvar ,
257+ }
258+
259+ // We cannot panic while holding a lock to `clones: Mutex<usize>` and therefore we cannot enter an
260+ // inconsistent state.
261+ impl RefUnwindSafe for Coordinate { }
262+
263263struct CoordinateDrop ( Arc < Coordinate > ) ;
264264
265265impl std:: ops:: Deref for CoordinateDrop {
@@ -272,7 +272,6 @@ impl std::ops::Deref for CoordinateDrop {
272272
273273impl Drop for CoordinateDrop {
274274 fn drop ( & mut self ) {
275- * self . 0 . clones . lock ( ) -= 1 ;
276275 self . 0 . cvar . notify_all ( ) ;
277276 }
278277}
0 commit comments