3838//! [`EventSource`](crate::EventSource) implementation to them.
3939
4040use 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 } ;
4243
4344use crate :: { EventSource , Interest , Mode , Poll , PostAction , Readiness , Token , TokenFactory } ;
4445
@@ -78,16 +79,79 @@ impl<T: AsRawFd> AsFd for FdWrapper<T> {
7879 }
7980}
8081
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+
81138/// A generic event source wrapping a FD-backed type
82139#[ derive( Debug ) ]
83140pub 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 > > ,
86145 /// The programmed interest
87146 pub interest : Interest ,
88147 /// The programmed mode
89148 pub mode : Mode ,
90149
150+ /// Back-reference to the poller.
151+ ///
152+ /// This is needed to drop the original file.
153+ poller : Option < Arc < Poller > > ,
154+
91155 // This token is used by the event loop logic to look up this source when an
92156 // event occurs.
93157 token : Option < Token > ,
@@ -101,30 +165,64 @@ impl<F: AsFd> Generic<F, std::io::Error> {
101165 /// [`std::io::Error`] as its error type.
102166 pub fn new ( file : F , interest : Interest , mode : Mode ) -> Generic < F , std:: io:: Error > {
103167 Generic {
104- file,
168+ file : Some ( NoIoDrop ( file ) ) ,
105169 interest,
106170 mode,
107171 token : None ,
172+ poller : None ,
108173 _error_type : PhantomData ,
109174 }
110175 }
111176
112177 /// Wrap a FD-backed type into a `Generic` event source using an arbitrary error type.
113178 pub fn new_with_error < E > ( file : F , interest : Interest , mode : Mode ) -> Generic < F , E > {
114179 Generic {
115- file,
180+ file : Some ( NoIoDrop ( file ) ) ,
116181 interest,
117182 mode,
118183 token : None ,
184+ poller : None ,
119185 _error_type : PhantomData ,
120186 }
121187 }
122188}
123189
124190impl < F : AsFd , E > Generic < F , E > {
125191 /// 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+ }
128226 }
129227}
130228
@@ -134,7 +232,7 @@ where
134232 E : Into < Box < dyn std:: error:: Error + Send + Sync > > ,
135233{
136234 type Event = Readiness ;
137- type Metadata = F ;
235+ type Metadata = NoIoDrop < F > ;
138236 type Ret = Result < PostAction , E > ;
139237 type Error = E ;
140238
@@ -152,13 +250,24 @@ where
152250 return Ok ( PostAction :: Continue ) ;
153251 }
154252
155- callback ( readiness, & mut self . file )
253+ callback ( readiness, self . file . as_mut ( ) . unwrap ( ) )
156254 }
157255
158256 fn register ( & mut self , poll : & mut Poll , token_factory : & mut TokenFactory ) -> crate :: Result < ( ) > {
159257 let token = token_factory. token ( ) ;
160258
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+ }
162271
163272 self . token = Some ( token) ;
164273 Ok ( ( ) )
@@ -171,14 +280,20 @@ where
171280 ) -> crate :: Result < ( ) > {
172281 let token = token_factory. token ( ) ;
173282
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+ ) ?;
175289
176290 self . token = Some ( token) ;
177291 Ok ( ( ) )
178292 }
179293
180294 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 ;
182297 self . token = None ;
183298 Ok ( ( ) )
184299 }
@@ -211,7 +326,7 @@ mod tests {
211326 // we have not registered for writability
212327 assert ! ( !readiness. writable) ;
213328 let mut buffer = vec ! [ 0 ; 10 ] ;
214- let ret = file. read ( & mut buffer) . unwrap ( ) ;
329+ let ret = ( & * * file) . read ( & mut buffer) . unwrap ( ) ;
215330 assert_eq ! ( ret, 6 ) ;
216331 assert_eq ! ( & buffer[ ..6 ] , & [ 1 , 2 , 3 , 4 , 5 , 6 ] ) ;
217332
@@ -286,7 +401,7 @@ mod tests {
286401 // we have not registered for writability
287402 assert ! ( !readiness. writable) ;
288403 let mut buffer = vec ! [ 0 ; 10 ] ;
289- let ret = file. read ( & mut buffer) . unwrap ( ) ;
404+ let ret = ( & * * file) . read ( & mut buffer) . unwrap ( ) ;
290405 assert_eq ! ( ret, 6 ) ;
291406 assert_eq ! ( & buffer[ ..6 ] , & [ 1 , 2 , 3 , 4 , 5 , 6 ] ) ;
292407
0 commit comments