1
1
//! Public API facades for the implementation details of [`Zalsa`] and [`ZalsaLocal`].
2
2
use std:: marker:: PhantomData ;
3
+ use std:: mem;
3
4
use std:: panic:: RefUnwindSafe ;
4
5
5
6
use crate :: database:: RawDatabase ;
@@ -25,8 +26,6 @@ pub struct StorageHandle<Db> {
25
26
26
27
impl < Db > Clone for StorageHandle < Db > {
27
28
fn clone ( & self ) -> Self {
28
- * self . coordinate . clones . lock ( ) += 1 ;
29
-
30
29
Self {
31
30
zalsa_impl : self . zalsa_impl . clone ( ) ,
32
31
coordinate : CoordinateDrop ( Arc :: clone ( & self . coordinate ) ) ,
@@ -53,7 +52,7 @@ impl<Db: Database> StorageHandle<Db> {
53
52
Self {
54
53
zalsa_impl : Arc :: new ( Zalsa :: new :: < Db > ( event_callback, jars) ) ,
55
54
coordinate : CoordinateDrop ( Arc :: new ( Coordinate {
56
- clones : Mutex :: new ( 1 ) ,
55
+ coordinate_lock : Mutex :: default ( ) ,
57
56
cvar : Default :: default ( ) ,
58
57
} ) ) ,
59
58
phantom : PhantomData ,
@@ -95,17 +94,6 @@ impl<Db> Drop for Storage<Db> {
95
94
}
96
95
}
97
96
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
-
109
97
impl < Db : Database > Default for Storage < Db > {
110
98
fn default ( ) -> Self {
111
99
Self :: new ( None )
@@ -168,12 +156,14 @@ impl<Db: Database> Storage<Db> {
168
156
. zalsa_impl
169
157
. event ( & || Event :: new ( EventKind :: DidSetCancellationFlag ) ) ;
170
158
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
+ } ;
177
167
// cancellation is done, so reset the flag
178
168
zalsa. runtime_mut ( ) . reset_cancellation_flag ( ) ;
179
169
zalsa
@@ -260,6 +250,16 @@ impl<Db: Database> Clone for Storage<Db> {
260
250
}
261
251
}
262
252
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
+
263
263
struct CoordinateDrop ( Arc < Coordinate > ) ;
264
264
265
265
impl std:: ops:: Deref for CoordinateDrop {
@@ -272,7 +272,6 @@ impl std::ops::Deref for CoordinateDrop {
272
272
273
273
impl Drop for CoordinateDrop {
274
274
fn drop ( & mut self ) {
275
- * self . 0 . clones . lock ( ) -= 1 ;
276
275
self . 0 . cvar . notify_all ( ) ;
277
276
}
278
277
}
0 commit comments