Skip to content

Commit 12f0a72

Browse files
committed
ndk/looper: Deprecate poll_all*() and document implied wake results
[Upstream clarified] that due to limitations in `ALooper`, the `poll*()` functions may not be able to distinguish an explicit `wake()` call from any other wakeup source, including callbacks, timeouts, fd events or even errors. Any return value from these functions should be treated as if a `Poll::Wake` event is also returned. While this is not only problematic to tell a wake apart from other events, it makes it impossible for the `poll_all*()` variants to return correctly as they will keep looping internally on callbacks (which are subsuming a wake event). According to [upstream `ALooper_pollAll()` documentation] this is considered "not safe" and the function is no longer allowed to be called. [Upstream clarified]: android/ndk#2020 [upstream `ALooper_pollAll()` documentation]: https://developer.android.com/ndk/reference/group/looper#alooper_pollall
1 parent e4a0b94 commit 12f0a72

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

ndk/src/looper.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,17 @@ bitflags::bitflags! {
7373
/// The poll result from a [`ThreadLooper`].
7474
#[derive(Debug)]
7575
pub enum Poll<'fd> {
76-
/// This looper was woken using [`ForeignLooper::wake()`]
76+
/// This looper was woken using [`ForeignLooper::wake()`].
77+
///
78+
/// # Note
79+
/// All possible return values from any of the `poll*()` functions on [`ThreadLooper`],
80+
/// *including [`Err`]*, may imply that the looper was also woken up.
7781
Wake,
7882
/// For [`ThreadLooper::poll_once*()`][ThreadLooper::poll_once()], an event was received and processed using a callback.
7983
Callback,
8084
/// For [`ThreadLooper::poll_*_timeout()`][ThreadLooper::poll_once_timeout()], the requested timeout was reached before any events.
8185
Timeout,
82-
/// An event was received
86+
/// An event was received.
8387
Event {
8488
ident: i32,
8589
/// # Safety
@@ -118,6 +122,9 @@ impl ThreadLooper {
118122

119123
/// Polls the looper, blocking on processing an event, but with a timeout in milliseconds.
120124
/// Give a timeout of `0` to make this non-blocking.
125+
///
126+
/// # Note
127+
/// Any return value, *including [`Err`]*, should be treated as if [`Poll::Wake`] was returned as well.
121128
fn poll_once_ms(&self, ms: i32) -> Result<Poll<'_>, LooperError> {
122129
let mut fd = -1;
123130
let mut events = -1;
@@ -141,6 +148,9 @@ impl ThreadLooper {
141148
}
142149

143150
/// Polls the looper, blocking on processing an event.
151+
///
152+
/// # Note
153+
/// Any return value, *including [`Err`]*, should be treated as if [`Poll::Wake`] was returned as well.
144154
#[inline]
145155
pub fn poll_once(&self) -> Result<Poll<'_>, LooperError> {
146156
self.poll_once_ms(-1)
@@ -151,6 +161,9 @@ impl ThreadLooper {
151161
///
152162
/// It panics if the timeout is larger than expressible as an [`i32`] of milliseconds (roughly 25
153163
/// days).
164+
///
165+
/// # Note
166+
/// Any return value, *including [`Err`]*, should be treated as if [`Poll::Wake`] was returned as well.
154167
#[inline]
155168
pub fn poll_once_timeout(&self, timeout: Duration) -> Result<Poll<'_>, LooperError> {
156169
self.poll_once_ms(
@@ -165,6 +178,7 @@ impl ThreadLooper {
165178
/// milliseconds. Give a timeout of `0` to make this non-blocking.
166179
///
167180
/// This function will never return [`Poll::Callback`].
181+
#[deprecated = "This function may not return even if [`Self::wake()`] is called. Call one of the `poll_once*()` methods instead."]
168182
fn poll_all_ms(&self, ms: i32) -> Result<Poll<'_>, LooperError> {
169183
let mut fd = -1;
170184
let mut events = -1;
@@ -189,8 +203,10 @@ impl ThreadLooper {
189203
/// Repeatedly polls the looper, blocking on processing an event.
190204
///
191205
/// This function will never return [`Poll::Callback`].
206+
#[deprecated = "This function may not return even if [`Self::wake()`] is called. Call one of the `poll_once*()` methods instead."]
192207
#[inline]
193208
pub fn poll_all(&self) -> Result<Poll<'_>, LooperError> {
209+
#[expect(deprecated)]
194210
self.poll_all_ms(-1)
195211
}
196212

@@ -201,8 +217,10 @@ impl ThreadLooper {
201217
///
202218
/// It panics if the timeout is larger than expressible as an [`i32`] of milliseconds (roughly 25
203219
/// days).
220+
#[deprecated = "This function may not return even if [`Self::wake()`] is called. Call one of the `poll_once*()` methods instead."]
204221
#[inline]
205222
pub fn poll_all_timeout(&self, timeout: Duration) -> Result<Poll<'_>, LooperError> {
223+
#[expect(deprecated)]
206224
self.poll_all_ms(
207225
timeout
208226
.as_millis()
@@ -309,6 +327,11 @@ impl ForeignLooper {
309327
}
310328

311329
/// Wakes the looper. An event of [`Poll::Wake`] will be sent.
330+
///
331+
/// # Note
332+
/// In case there are other events to handle, `poll*()` functions may not return [`Poll::Wake`]
333+
/// at all. Any [`Poll`] event and [`Err`] returned by `poll*()` could imply that the looper
334+
/// has also been woken.
312335
pub fn wake(&self) {
313336
unsafe { ffi::ALooper_wake(self.ptr.as_ptr()) }
314337
}

0 commit comments

Comments
 (0)