1
+ use std:: pin:: Pin ;
1
2
use std:: thread:: ThreadId ;
2
3
3
4
use parking_lot:: MutexGuard ;
4
5
use rustc_hash:: FxHashMap ;
5
6
use smallvec:: SmallVec ;
6
7
7
8
use crate :: key:: DatabaseKeyIndex ;
9
+ use crate :: runtime:: dependency_graph:: edge:: EdgeCondvar ;
8
10
use crate :: runtime:: WaitResult ;
9
11
10
12
#[ derive( Debug , Default ) ]
@@ -61,7 +63,12 @@ impl DependencyGraph {
61
63
to_id : ThreadId ,
62
64
query_mutex_guard : QueryMutexGuard ,
63
65
) -> WaitResult {
64
- let edge = me. add_edge ( from_id, database_key, to_id) ;
66
+ let cvar = std:: pin:: pin!( EdgeCondvar :: default ( ) ) ;
67
+ let cvar = cvar. as_ref ( ) ;
68
+ // SAFETY: We are blocking until the result is removed from `DependencyGraph::wait_results`
69
+ // at which point the `edge` won't signal the condvar anymore.
70
+ // As such we are keeping the cond var alive until the reference in the edge drops.
71
+ unsafe { me. add_edge ( from_id, database_key, to_id, cvar) } ;
65
72
66
73
// Release the mutex that prevents `database_key`
67
74
// from completing, now that the edge has been added.
@@ -72,29 +79,35 @@ impl DependencyGraph {
72
79
debug_assert ! ( !me. edges. contains_key( & from_id) ) ;
73
80
return result;
74
81
}
75
- edge . wait ( & mut me) ;
82
+ cvar . wait ( & mut me) ;
76
83
}
77
84
}
78
85
79
86
/// Helper for `block_on`: performs actual graph modification
80
87
/// to add a dependency edge from `from_id` to `to_id`, which is
81
88
/// computing `database_key`.
82
- fn add_edge (
89
+ ///
90
+ /// # Safety
91
+ ///
92
+ /// The caller needs to keep the referent of `cvar` alive until the corresponding
93
+ /// [`Self::wait_results`] entry has been inserted.
94
+ unsafe fn add_edge (
83
95
& mut self ,
84
96
from_id : ThreadId ,
85
97
database_key : DatabaseKeyIndex ,
86
98
to_id : ThreadId ,
87
- ) -> edge:: EdgeGuard {
99
+ cvar : Pin < & EdgeCondvar > ,
100
+ ) {
88
101
assert_ne ! ( from_id, to_id) ;
89
102
debug_assert ! ( !self . edges. contains_key( & from_id) ) ;
90
103
debug_assert ! ( !self . depends_on( to_id, from_id) ) ;
91
- let ( edge, guard) = edge:: Edge :: new ( to_id) ;
104
+ // SAFETY: The caller is responsible for ensuring that the `EdgeGuard` outlives the `Edge`.
105
+ let edge = unsafe { edge:: Edge :: new ( to_id, cvar) } ;
92
106
self . edges . insert ( from_id, edge) ;
93
107
self . query_dependents
94
108
. entry ( database_key)
95
109
. or_default ( )
96
110
. push ( from_id) ;
97
- guard
98
111
}
99
112
100
113
/// Invoked when runtime `to_id` completes executing
@@ -128,45 +141,49 @@ impl DependencyGraph {
128
141
}
129
142
130
143
mod edge {
131
- use std:: sync:: Arc ;
132
- use std:: thread:: ThreadId ;
144
+ use std:: { pin:: Pin , thread:: ThreadId } ;
145
+
146
+ use parking_lot:: Condvar ;
133
147
134
- use parking_lot:: MutexGuard ;
148
+ #[ derive( Default , Debug ) ]
149
+ pub ( super ) struct EdgeCondvar {
150
+ condvar : Condvar ,
151
+ _phantom_pin : std:: marker:: PhantomPinned ,
152
+ }
135
153
136
- use crate :: runtime:: dependency_graph:: DependencyGraph ;
154
+ impl EdgeCondvar {
155
+ #[ inline]
156
+ pub ( super ) fn wait < T : ?Sized > ( & self , mutex_guard : & mut parking_lot:: MutexGuard < ' _ , T > ) {
157
+ self . condvar . wait ( mutex_guard)
158
+ }
159
+ }
137
160
138
161
#[ derive( Debug ) ]
139
162
pub ( super ) struct Edge {
140
163
pub ( super ) blocked_on_id : ThreadId ,
141
164
142
165
/// Signalled whenever a query with dependents completes.
143
166
/// Allows those dependents to check if they are ready to unblock.
144
- condvar : Arc < parking_lot:: Condvar > ,
145
- }
146
-
147
- pub struct EdgeGuard {
148
- condvar : Arc < parking_lot:: Condvar > ,
149
- }
150
-
151
- impl EdgeGuard {
152
- pub fn wait ( & self , mutex_guard : & mut MutexGuard < ' _ , DependencyGraph > ) {
153
- self . condvar . wait ( mutex_guard)
154
- }
167
+ // condvar: unsafe<'stack_frame> Pin<&'stack_frame parking_lot::Condvar>,
168
+ condvar : Pin < & ' static EdgeCondvar > ,
155
169
}
156
170
157
171
impl Edge {
158
- pub ( super ) fn new ( blocked_on_id : ThreadId ) -> ( Self , EdgeGuard ) {
159
- let condvar = Arc :: new ( parking_lot:: Condvar :: new ( ) ) ;
160
- let edge = Self {
172
+ /// # SAFETY
173
+ ///
174
+ /// The caller must ensure that the [`EdgeCondvar`] is kept alive until the [`Edge`] is dropped.
175
+ pub ( super ) unsafe fn new ( blocked_on_id : ThreadId , condvar : Pin < & EdgeCondvar > ) -> Self {
176
+ Self {
161
177
blocked_on_id,
162
- condvar : condvar . clone ( ) ,
163
- } ;
164
- let edge_guard = EdgeGuard { condvar } ;
165
- ( edge , edge_guard )
178
+ condvar : unsafe {
179
+ std :: mem :: transmute :: < Pin < & EdgeCondvar > , Pin < & ' static EdgeCondvar > > ( condvar )
180
+ } ,
181
+ }
166
182
}
167
183
184
+ #[ inline]
168
185
pub ( super ) fn notify ( self ) {
169
- self . condvar . notify_one ( ) ;
186
+ self . condvar . condvar . notify_one ( ) ;
170
187
}
171
188
}
172
189
}
0 commit comments