Skip to content

Commit

Permalink
looper: Provide event value to file descriptor poll callback (#435)
Browse files Browse the repository at this point in the history
When `looper` calls a callback that triggered for a poll on a file
descriptor it provides the reason for the wakeup, because users are
allowed to register multiple.  Hence it is important for the user to
know the trigger reason to enact on the result appropriately.  E.g. a
`HANGUP` typically requires the callback to be deregistered by returning
`false`, as the other end (for a `pipe()` or `socket()`) has been closed
and this file descriptor should no longer trigger any other event.

Note that various events are received by this callback regardless of
whether the user registered it with that flag in `events`. This is all
reflected by updating the documentation comments for `FdEvent` based
on upstream Android documentation.

Keep in mind that `FdEvent` is a `bitflag`, and Android uses that to
batch up multiple events.  E.g. writing to a `pipe()` and closing the
write `fd` - while the read `fd` is registered in a callback - causes
the callback (from a subsequent `looper.poll*()`) to be called with
`INPUT | HANGUP`, indicating that there is data to read but that the
file descriptor will be dormant after that.
  • Loading branch information
MarijnS95 authored Oct 10, 2023
1 parent 3b3aae9 commit 3b124fa
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 4 deletions.
1 change: 1 addition & 0 deletions ndk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
- hardware_buffer: Add `id()` to retrieve a system-wide unique identifier for a `HardwareBuffer`. (#428)
- **Breaking:** bitmap: Strip `Android` prefix from structs and enums, and `Bitmap` from `Result`. (#430)
- **Breaking:** `raw-window-handle 0.5` support is now behind an _optional_ `rwh_05` crate feature and `raw-window-handle` `0.4` and `0.6` support is provided via the new `rwh_04` and (default-enabled) `rwh_06` crate features. (#434)
- **Breaking:** looper: Provide `event` value to file descriptor poll callback. (#435)

# 0.7.0 (2022-07-24)

Expand Down
37 changes: 33 additions & 4 deletions ndk/src/looper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,37 @@ pub struct ThreadLooper {

bitflags! {
/// Flags for file descriptor events that a looper can monitor.
///
/// These flag bits can be combined to monitor multiple events at once.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct FdEvent: u32 {
/// The file descriptor is available for read operations.
#[doc(alias = "ALOOPER_EVENT_INPUT")]
const INPUT = ffi::ALOOPER_EVENT_INPUT;
/// The file descriptor is available for write operations.
#[doc(alias = "ALOOPER_EVENT_OUTPUT")]
const OUTPUT = ffi::ALOOPER_EVENT_OUTPUT;
/// The file descriptor has encountered an error condition.
///
/// The looper always sends notifications about errors; it is not necessary to specify this
/// event flag in the requested event set.
#[doc(alias = "ALOOPER_EVENT_ERROR")]
const ERROR = ffi::ALOOPER_EVENT_ERROR;
/// The file descriptor was hung up.
///
/// For example, indicates that the remote end of a pipe or socket was closed.
///
/// The looper always sends notifications about hangups; it is not necessary to specify this
/// event flag in the requested event set.
#[doc(alias = "ALOOPER_EVENT_HANGUP")]
const HANGUP = ffi::ALOOPER_EVENT_HANGUP;
/// The file descriptor is invalid.
///
/// For example, the file descriptor was closed prematurely.
///
/// The looper always sends notifications about invalid file descriptors; it is not
/// necessary to specify this event flag in the requested event set.
#[doc(alias = "ALOOPER_EVENT_INVALID")]
const INVALID = ffi::ALOOPER_EVENT_INVALID;
}
}
Expand Down Expand Up @@ -301,20 +326,24 @@ impl ForeignLooper {
/// The caller should guarantee that this file descriptor stays open until it is removed via
/// [`remove_fd()`][Self::remove_fd()] or by returning [`false`] from the callback, and for
/// however long the caller wishes to use this file descriptor inside and after the callback.
pub fn add_fd_with_callback<F: FnMut(BorrowedFd<'_>) -> bool>(
#[doc(alias = "ALooper_addFd")]
pub fn add_fd_with_callback<F: FnMut(BorrowedFd<'_>, FdEvent) -> bool>(
&self,
fd: BorrowedFd<'_>,
events: FdEvent,
callback: F,
) -> Result<(), LooperError> {
extern "C" fn cb_handler<F: FnMut(BorrowedFd<'_>) -> bool>(
extern "C" fn cb_handler<F: FnMut(BorrowedFd<'_>, FdEvent) -> bool>(
fd: RawFd,
_events: i32,
events: i32,
data: *mut c_void,
) -> i32 {
abort_on_panic(|| unsafe {
let mut cb = ManuallyDrop::new(Box::<F>::from_raw(data as *mut _));
let keep_registered = cb(BorrowedFd::borrow_raw(fd));
let events = FdEvent::from_bits_retain(
events.try_into().expect("Unexpected sign bit in `events`"),
);
let keep_registered = cb(BorrowedFd::borrow_raw(fd), events);
if !keep_registered {
ManuallyDrop::into_inner(cb);
}
Expand Down

0 comments on commit 3b124fa

Please sign in to comment.