38
38
//! [`EventSource`](crate::EventSource) implementation to them.
39
39
40
40
use io_lifetimes:: { AsFd , BorrowedFd } ;
41
- use std:: { marker:: PhantomData , ops, os:: unix:: io:: AsRawFd } ;
41
+ use polling:: Poller ;
42
+ use std:: { borrow, marker:: PhantomData , ops, os:: unix:: io:: AsRawFd , sync:: Arc } ;
42
43
43
44
use crate :: { EventSource , Interest , Mode , Poll , PostAction , Readiness , Token , TokenFactory } ;
44
45
@@ -78,16 +79,79 @@ impl<T: AsRawFd> AsFd for FdWrapper<T> {
78
79
}
79
80
}
80
81
82
+ /// A wrapper around a type that doesn't expose it mutably safely.
83
+ ///
84
+ /// The [`EventSource`] trait's `Metadata` type demands mutable access to the inner I/O source.
85
+ /// However, the inner polling source used by `calloop` keeps the handle-based equivalent of an
86
+ /// immutable pointer to the underlying object's I/O handle. Therefore, if the inner source is
87
+ /// dropped, this leaves behind a dangling pointer which immediately invokes undefined behavior
88
+ /// on the next poll of the event loop.
89
+ ///
90
+ /// In order to prevent this from happening, the [`Generic`] I/O source must not directly expose
91
+ /// a mutable reference to the underlying handle. This type wraps around the underlying handle and
92
+ /// easily allows users to take immutable (`&`) references to the type, but makes mutable (`&mut`)
93
+ /// references unsafe to get. Therefore, it prevents the source from being moved out and dropped
94
+ /// while it is still registered in the event loop.
95
+ ///
96
+ /// [`EventSource`]: crate::EventSource
97
+ #[ derive( Debug ) ]
98
+ pub struct NoIoDrop < T > ( T ) ;
99
+
100
+ impl < T > NoIoDrop < T > {
101
+ /// Get a mutable reference.
102
+ ///
103
+ /// # Safety
104
+ ///
105
+ /// The inner type's I/O source must not be dropped.
106
+ pub unsafe fn get_mut ( & mut self ) -> & mut T {
107
+ & mut self . 0
108
+ }
109
+ }
110
+
111
+ impl < T > AsRef < T > for NoIoDrop < T > {
112
+ fn as_ref ( & self ) -> & T {
113
+ & self . 0
114
+ }
115
+ }
116
+
117
+ impl < T > borrow:: Borrow < T > for NoIoDrop < T > {
118
+ fn borrow ( & self ) -> & T {
119
+ & self . 0
120
+ }
121
+ }
122
+
123
+ impl < T > ops:: Deref for NoIoDrop < T > {
124
+ type Target = T ;
125
+
126
+ fn deref ( & self ) -> & Self :: Target {
127
+ & self . 0
128
+ }
129
+ }
130
+
131
+ impl < T : AsFd > AsFd for NoIoDrop < T > {
132
+ fn as_fd ( & self ) -> BorrowedFd < ' _ > {
133
+ // SAFETY: The innter type is not mutated.
134
+ self . 0 . as_fd ( )
135
+ }
136
+ }
137
+
81
138
/// A generic event source wrapping a FD-backed type
82
139
#[ derive( Debug ) ]
83
140
pub struct Generic < F : AsFd , E = std:: io:: Error > {
84
- /// The wrapped FD-backed type
85
- pub file : F ,
141
+ /// The wrapped FD-backed type.
142
+ ///
143
+ /// This must be deregistered before it is dropped.
144
+ file : Option < NoIoDrop < F > > ,
86
145
/// The programmed interest
87
146
pub interest : Interest ,
88
147
/// The programmed mode
89
148
pub mode : Mode ,
90
149
150
+ /// Back-reference to the poller.
151
+ ///
152
+ /// This is needed to drop the original file.
153
+ poller : Option < Arc < Poller > > ,
154
+
91
155
// This token is used by the event loop logic to look up this source when an
92
156
// event occurs.
93
157
token : Option < Token > ,
@@ -101,30 +165,64 @@ impl<F: AsFd> Generic<F, std::io::Error> {
101
165
/// [`std::io::Error`] as its error type.
102
166
pub fn new ( file : F , interest : Interest , mode : Mode ) -> Generic < F , std:: io:: Error > {
103
167
Generic {
104
- file,
168
+ file : Some ( NoIoDrop ( file ) ) ,
105
169
interest,
106
170
mode,
107
171
token : None ,
172
+ poller : None ,
108
173
_error_type : PhantomData ,
109
174
}
110
175
}
111
176
112
177
/// Wrap a FD-backed type into a `Generic` event source using an arbitrary error type.
113
178
pub fn new_with_error < E > ( file : F , interest : Interest , mode : Mode ) -> Generic < F , E > {
114
179
Generic {
115
- file,
180
+ file : Some ( NoIoDrop ( file ) ) ,
116
181
interest,
117
182
mode,
118
183
token : None ,
184
+ poller : None ,
119
185
_error_type : PhantomData ,
120
186
}
121
187
}
122
188
}
123
189
124
190
impl < F : AsFd , E > Generic < F , E > {
125
191
/// Unwrap the `Generic` source to retrieve the underlying type
126
- pub fn unwrap ( self ) -> F {
127
- self . file
192
+ pub fn unwrap ( mut self ) -> F {
193
+ let NoIoDrop ( file) = self . file . take ( ) . unwrap ( ) ;
194
+
195
+ // Remove it from the poller.
196
+ if let Some ( poller) = self . poller . take ( ) {
197
+ poller. delete ( file. as_fd ( ) ) . ok ( ) ;
198
+ }
199
+
200
+ file
201
+ }
202
+
203
+ /// Get a reference to the underlying type.
204
+ pub fn get_ref ( & self ) -> & F {
205
+ & self . file . as_ref ( ) . unwrap ( ) . 0
206
+ }
207
+
208
+ /// Get a mutable reference to the underlying type.
209
+ ///
210
+ /// # Safety
211
+ ///
212
+ /// This is unsafe because it allows you to modify the underlying type, which
213
+ /// allows you to drop the underlying event source. Dropping the underlying source
214
+ /// leads to a dangling reference.
215
+ pub unsafe fn get_mut ( & mut self ) -> & mut F {
216
+ self . file . as_mut ( ) . unwrap ( ) . get_mut ( )
217
+ }
218
+ }
219
+
220
+ impl < F : AsFd , E > Drop for Generic < F , E > {
221
+ fn drop ( & mut self ) {
222
+ // Remove it from the poller.
223
+ if let ( Some ( file) , Some ( poller) ) = ( self . file . take ( ) , self . poller . take ( ) ) {
224
+ poller. delete ( file. as_fd ( ) ) . ok ( ) ;
225
+ }
128
226
}
129
227
}
130
228
@@ -134,7 +232,7 @@ where
134
232
E : Into < Box < dyn std:: error:: Error + Send + Sync > > ,
135
233
{
136
234
type Event = Readiness ;
137
- type Metadata = F ;
235
+ type Metadata = NoIoDrop < F > ;
138
236
type Ret = Result < PostAction , E > ;
139
237
type Error = E ;
140
238
@@ -152,13 +250,24 @@ where
152
250
return Ok ( PostAction :: Continue ) ;
153
251
}
154
252
155
- callback ( readiness, & mut self . file )
253
+ callback ( readiness, self . file . as_mut ( ) . unwrap ( ) )
156
254
}
157
255
158
256
fn register ( & mut self , poll : & mut Poll , token_factory : & mut TokenFactory ) -> crate :: Result < ( ) > {
159
257
let token = token_factory. token ( ) ;
160
258
161
- poll. register ( & self . file , self . interest , self . mode , token) ?;
259
+ // Make sure we can use the poller to deregister if need be.
260
+ self . poller = Some ( poll. poller ( ) . clone ( ) ) ;
261
+
262
+ // SAFETY: We've now ensured that we have a poller to deregister with.
263
+ unsafe {
264
+ poll. register (
265
+ & self . file . as_ref ( ) . unwrap ( ) . 0 ,
266
+ self . interest ,
267
+ self . mode ,
268
+ token,
269
+ ) ?;
270
+ }
162
271
163
272
self . token = Some ( token) ;
164
273
Ok ( ( ) )
@@ -171,14 +280,20 @@ where
171
280
) -> crate :: Result < ( ) > {
172
281
let token = token_factory. token ( ) ;
173
282
174
- poll. reregister ( & self . file , self . interest , self . mode , token) ?;
283
+ poll. reregister (
284
+ & self . file . as_ref ( ) . unwrap ( ) . 0 ,
285
+ self . interest ,
286
+ self . mode ,
287
+ token,
288
+ ) ?;
175
289
176
290
self . token = Some ( token) ;
177
291
Ok ( ( ) )
178
292
}
179
293
180
294
fn unregister ( & mut self , poll : & mut Poll ) -> crate :: Result < ( ) > {
181
- poll. unregister ( & self . file ) ?;
295
+ poll. unregister ( & self . file . as_ref ( ) . unwrap ( ) . 0 ) ?;
296
+ self . poller = None ;
182
297
self . token = None ;
183
298
Ok ( ( ) )
184
299
}
@@ -211,7 +326,7 @@ mod tests {
211
326
// we have not registered for writability
212
327
assert ! ( !readiness. writable) ;
213
328
let mut buffer = vec ! [ 0 ; 10 ] ;
214
- let ret = file. read ( & mut buffer) . unwrap ( ) ;
329
+ let ret = ( & * * file) . read ( & mut buffer) . unwrap ( ) ;
215
330
assert_eq ! ( ret, 6 ) ;
216
331
assert_eq ! ( & buffer[ ..6 ] , & [ 1 , 2 , 3 , 4 , 5 , 6 ] ) ;
217
332
@@ -286,7 +401,7 @@ mod tests {
286
401
// we have not registered for writability
287
402
assert ! ( !readiness. writable) ;
288
403
let mut buffer = vec ! [ 0 ; 10 ] ;
289
- let ret = file. read ( & mut buffer) . unwrap ( ) ;
404
+ let ret = ( & * * file) . read ( & mut buffer) . unwrap ( ) ;
290
405
assert_eq ! ( ret, 6 ) ;
291
406
assert_eq ! ( & buffer[ ..6 ] , & [ 1 , 2 , 3 , 4 , 5 , 6 ] ) ;
292
407
0 commit comments