12
12
use bitflags:: bitflags;
13
13
use std:: mem:: ManuallyDrop ;
14
14
use std:: os:: raw:: c_void;
15
- use std:: os:: unix:: io:: RawFd ;
15
+ // TODO: Import from std::os::fd::{} since Rust 1.66
16
+ use std:: os:: unix:: io:: { AsRawFd , BorrowedFd , RawFd } ;
16
17
use std:: ptr;
17
- use std:: ptr:: NonNull ;
18
18
use std:: time:: Duration ;
19
19
use thiserror:: Error ;
20
20
@@ -42,7 +42,7 @@ bitflags! {
42
42
43
43
/// The poll result from a [`ThreadLooper`].
44
44
#[ derive( Debug ) ]
45
- pub enum Poll {
45
+ pub enum Poll < ' fd > {
46
46
/// This looper was woken using [`ForeignLooper::wake()`]
47
47
Wake ,
48
48
/// For [`ThreadLooper::poll_once*()`][ThreadLooper::poll_once()], an event was received and processed using a callback.
@@ -52,7 +52,10 @@ pub enum Poll {
52
52
/// An event was received
53
53
Event {
54
54
ident : i32 ,
55
- fd : RawFd ,
55
+ /// # Safety
56
+ /// The caller should guarantee that this file descriptor remains open after it was added
57
+ /// via [`ForeignLooper::add_fd()`] or [`ForeignLooper::add_fd_with_callback()`].
58
+ fd : BorrowedFd < ' fd > ,
56
59
events : FdEvent ,
57
60
data : * mut c_void ,
58
61
} ,
@@ -67,7 +70,7 @@ impl ThreadLooper {
67
70
pub fn prepare ( ) -> Self {
68
71
unsafe {
69
72
let ptr = ffi:: ALooper_prepare ( ffi:: ALOOPER_PREPARE_ALLOW_NON_CALLBACKS as _ ) ;
70
- let foreign = ForeignLooper :: from_ptr ( NonNull :: new ( ptr) . expect ( "looper non null" ) ) ;
73
+ let foreign = ForeignLooper :: from_ptr ( ptr :: NonNull :: new ( ptr) . expect ( "looper non null" ) ) ;
71
74
Self {
72
75
_marker : std:: marker:: PhantomData ,
73
76
foreign,
@@ -83,9 +86,11 @@ impl ThreadLooper {
83
86
} )
84
87
}
85
88
86
- fn poll_once_ms ( & self , ms : i32 ) -> Result < Poll , LooperError > {
87
- let mut fd: RawFd = -1 ;
88
- let mut events: i32 = -1 ;
89
+ /// Polls the looper, blocking on processing an event, but with a timeout in milliseconds.
90
+ /// Give a timeout of `0` to make this non-blocking.
91
+ fn poll_once_ms ( & self , ms : i32 ) -> Result < Poll < ' _ > , LooperError > {
92
+ let mut fd = -1 ;
93
+ let mut events = -1 ;
89
94
let mut data: * mut c_void = ptr:: null_mut ( ) ;
90
95
match unsafe { ffi:: ALooper_pollOnce ( ms, & mut fd, & mut events, & mut data) } {
91
96
ffi:: ALOOPER_POLL_WAKE => Ok ( Poll :: Wake ) ,
@@ -94,7 +99,9 @@ impl ThreadLooper {
94
99
ffi:: ALOOPER_POLL_ERROR => Err ( LooperError ) ,
95
100
ident if ident >= 0 => Ok ( Poll :: Event {
96
101
ident,
97
- fd,
102
+ // SAFETY: Even though this FD at least shouldn't outlive self, a user could have
103
+ // closed it after calling add_fd or add_fd_with_callback.
104
+ fd : unsafe { BorrowedFd :: borrow_raw ( fd) } ,
98
105
events : FdEvent :: from_bits ( events as u32 )
99
106
. expect ( "poll event contains unknown bits" ) ,
100
107
data,
@@ -105,17 +112,17 @@ impl ThreadLooper {
105
112
106
113
/// Polls the looper, blocking on processing an event.
107
114
#[ inline]
108
- pub fn poll_once ( & self ) -> Result < Poll , LooperError > {
115
+ pub fn poll_once ( & self ) -> Result < Poll < ' _ > , LooperError > {
109
116
self . poll_once_ms ( -1 )
110
117
}
111
118
112
- /// Polls the looper, blocking on processing an event, but with a timeout. Give a timeout of 0
113
- /// to make this non-blocking.
119
+ /// Polls the looper, blocking on processing an event, but with a timeout. Give a timeout of
120
+ /// [`Duration::ZERO`] to make this non-blocking.
114
121
///
115
122
/// It panics if the timeout is larger than expressible as an [`i32`] of milliseconds (roughly 25
116
123
/// days).
117
124
#[ inline]
118
- pub fn poll_once_timeout ( & self , timeout : Duration ) -> Result < Poll , LooperError > {
125
+ pub fn poll_once_timeout ( & self , timeout : Duration ) -> Result < Poll < ' _ > , LooperError > {
119
126
self . poll_once_ms (
120
127
timeout
121
128
. as_millis ( )
@@ -124,17 +131,23 @@ impl ThreadLooper {
124
131
)
125
132
}
126
133
127
- fn poll_all_ms ( & self , ms : i32 ) -> Result < Poll , LooperError > {
128
- let mut fd: RawFd = -1 ;
129
- let mut events: i32 = -1 ;
134
+ /// Repeatedly polls the looper, blocking on processing an event, but with a timeout in
135
+ /// milliseconds. Give a timeout of `0` to make this non-blocking.
136
+ ///
137
+ /// This function will never return [`Poll::Callback`].
138
+ fn poll_all_ms ( & self , ms : i32 ) -> Result < Poll < ' _ > , LooperError > {
139
+ let mut fd = -1 ;
140
+ let mut events = -1 ;
130
141
let mut data: * mut c_void = ptr:: null_mut ( ) ;
131
142
match unsafe { ffi:: ALooper_pollAll ( ms, & mut fd, & mut events, & mut data) } {
132
143
ffi:: ALOOPER_POLL_WAKE => Ok ( Poll :: Wake ) ,
133
144
ffi:: ALOOPER_POLL_TIMEOUT => Ok ( Poll :: Timeout ) ,
134
145
ffi:: ALOOPER_POLL_ERROR => Err ( LooperError ) ,
135
146
ident if ident >= 0 => Ok ( Poll :: Event {
136
147
ident,
137
- fd,
148
+ // SAFETY: Even though this FD at least shouldn't outlive self, a user could have
149
+ // closed it after calling add_fd or add_fd_with_callback.
150
+ fd : unsafe { BorrowedFd :: borrow_raw ( fd) } ,
138
151
events : FdEvent :: from_bits ( events as u32 )
139
152
. expect ( "poll event contains unknown bits" ) ,
140
153
data,
@@ -147,19 +160,19 @@ impl ThreadLooper {
147
160
///
148
161
/// This function will never return [`Poll::Callback`].
149
162
#[ inline]
150
- pub fn poll_all ( & self ) -> Result < Poll , LooperError > {
163
+ pub fn poll_all ( & self ) -> Result < Poll < ' _ > , LooperError > {
151
164
self . poll_all_ms ( -1 )
152
165
}
153
166
154
- /// Repeatedly polls the looper, blocking on processing an event, but with a timeout. Give a
155
- /// timeout of 0 to make this non-blocking.
167
+ /// Repeatedly polls the looper, blocking on processing an event, but with a timeout. Give a
168
+ /// timeout of [`Duration::ZERO`] to make this non-blocking.
156
169
///
157
170
/// This function will never return [`Poll::Callback`].
158
171
///
159
172
/// It panics if the timeout is larger than expressible as an [`i32`] of milliseconds (roughly 25
160
173
/// days).
161
174
#[ inline]
162
- pub fn poll_all_timeout ( & self , timeout : Duration ) -> Result < Poll , LooperError > {
175
+ pub fn poll_all_timeout ( & self , timeout : Duration ) -> Result < Poll < ' _ > , LooperError > {
163
176
self . poll_all_ms (
164
177
timeout
165
178
. as_millis ( )
@@ -183,7 +196,7 @@ impl ThreadLooper {
183
196
/// [`ALooper *`]: https://developer.android.com/ndk/reference/group/looper#alooper
184
197
#[ derive( Debug ) ]
185
198
pub struct ForeignLooper {
186
- ptr : NonNull < ffi:: ALooper > ,
199
+ ptr : ptr :: NonNull < ffi:: ALooper > ,
187
200
}
188
201
189
202
unsafe impl Send for ForeignLooper { }
@@ -208,7 +221,8 @@ impl ForeignLooper {
208
221
/// Returns the looper associated with the current thread, if any.
209
222
#[ inline]
210
223
pub fn for_thread ( ) -> Option < Self > {
211
- NonNull :: new ( unsafe { ffi:: ALooper_forThread ( ) } ) . map ( |ptr| unsafe { Self :: from_ptr ( ptr) } )
224
+ ptr:: NonNull :: new ( unsafe { ffi:: ALooper_forThread ( ) } )
225
+ . map ( |ptr| unsafe { Self :: from_ptr ( ptr) } )
212
226
}
213
227
214
228
/// Construct a [`ForeignLooper`] object from the given pointer.
@@ -217,14 +231,14 @@ impl ForeignLooper {
217
231
/// By calling this function, you guarantee that the pointer is a valid, non-null pointer to an
218
232
/// NDK [`ffi::ALooper`].
219
233
#[ inline]
220
- pub unsafe fn from_ptr ( ptr : NonNull < ffi:: ALooper > ) -> Self {
234
+ pub unsafe fn from_ptr ( ptr : ptr :: NonNull < ffi:: ALooper > ) -> Self {
221
235
ffi:: ALooper_acquire ( ptr. as_ptr ( ) ) ;
222
236
Self { ptr }
223
237
}
224
238
225
239
/// Returns a pointer to the NDK `ALooper` object.
226
240
#[ inline]
227
- pub fn ptr ( & self ) -> NonNull < ffi:: ALooper > {
241
+ pub fn ptr ( & self ) -> ptr :: NonNull < ffi:: ALooper > {
228
242
self . ptr
229
243
}
230
244
@@ -237,21 +251,26 @@ impl ForeignLooper {
237
251
///
238
252
/// See also [the NDK
239
253
/// docs](https://developer.android.com/ndk/reference/group/looper.html#alooper_addfd).
254
+ ///
255
+ /// # Safety
256
+ /// The caller should guarantee that this file descriptor stays open until it is removed via
257
+ /// [`remove_fd()`][Self::remove_fd()], and for however long the caller wishes to use this file
258
+ /// descriptor when it is returned in [`Poll::Event::fd`].
240
259
241
260
// `ALooper_addFd` won't dereference `data`; it will only pass it on to the event.
242
261
// Optionally dereferencing it there already enforces `unsafe` context.
243
262
#[ allow( clippy:: not_unsafe_ptr_arg_deref) ]
244
263
pub fn add_fd (
245
264
& self ,
246
- fd : RawFd ,
265
+ fd : BorrowedFd < ' _ > ,
247
266
ident : i32 ,
248
267
events : FdEvent ,
249
268
data : * mut c_void ,
250
269
) -> Result < ( ) , LooperError > {
251
270
match unsafe {
252
271
ffi:: ALooper_addFd (
253
272
self . ptr . as_ptr ( ) ,
254
- fd,
273
+ fd. as_raw_fd ( ) ,
255
274
ident,
256
275
events. bits ( ) as i32 ,
257
276
None ,
@@ -274,20 +293,25 @@ impl ForeignLooper {
274
293
///
275
294
/// Note that this will leak a [`Box`] unless the callback returns [`false`] to unregister
276
295
/// itself.
277
- pub fn add_fd_with_callback < F : FnMut ( RawFd ) -> bool > (
296
+ ///
297
+ /// # Safety
298
+ /// The caller should guarantee that this file descriptor stays open until it is removed via
299
+ /// [`remove_fd()`][Self::remove_fd()] or by returning [`false`] from the callback, and for
300
+ /// however long the caller wishes to use this file descriptor inside and after the callback.
301
+ pub fn add_fd_with_callback < F : FnMut ( BorrowedFd < ' _ > ) -> bool > (
278
302
& self ,
279
- fd : RawFd ,
303
+ fd : BorrowedFd < ' _ > ,
280
304
events : FdEvent ,
281
305
callback : F ,
282
306
) -> Result < ( ) , LooperError > {
283
- extern "C" fn cb_handler < F : FnMut ( RawFd ) -> bool > (
307
+ extern "C" fn cb_handler < F : FnMut ( BorrowedFd < ' _ > ) -> bool > (
284
308
fd : RawFd ,
285
309
_events : i32 ,
286
310
data : * mut c_void ,
287
311
) -> i32 {
288
312
unsafe {
289
313
let mut cb = ManuallyDrop :: new ( Box :: < F > :: from_raw ( data as * mut _ ) ) ;
290
- let keep_registered = cb ( fd ) ;
314
+ let keep_registered = cb ( BorrowedFd :: borrow_raw ( fd ) ) ;
291
315
if !keep_registered {
292
316
ManuallyDrop :: into_inner ( cb) ;
293
317
}
@@ -298,7 +322,7 @@ impl ForeignLooper {
298
322
match unsafe {
299
323
ffi:: ALooper_addFd (
300
324
self . ptr . as_ptr ( ) ,
301
- fd,
325
+ fd. as_raw_fd ( ) ,
302
326
ffi:: ALOOPER_POLL_CALLBACK ,
303
327
events. bits ( ) as i32 ,
304
328
Some ( cb_handler :: < F > ) ,
@@ -328,8 +352,8 @@ impl ForeignLooper {
328
352
/// Note that unregistering a file descriptor with callback will leak a [`Box`] created in
329
353
/// [`add_fd_with_callback()`][Self::add_fd_with_callback()]. Consider returning [`false`]
330
354
/// from the callback instead to drop it.
331
- pub fn remove_fd ( & self , fd : RawFd ) -> Result < bool , LooperError > {
332
- match unsafe { ffi:: ALooper_removeFd ( self . ptr . as_ptr ( ) , fd) } {
355
+ pub fn remove_fd ( & self , fd : BorrowedFd < ' _ > ) -> Result < bool , LooperError > {
356
+ match unsafe { ffi:: ALooper_removeFd ( self . ptr . as_ptr ( ) , fd. as_raw_fd ( ) ) } {
333
357
1 => Ok ( true ) ,
334
358
0 => Ok ( false ) ,
335
359
-1 => Err ( LooperError ) ,
0 commit comments