mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-07-08 10:25:20 +02:00
ANDROID: rust_binder: add epoll support
This adds epoll integration, allowing you to get an epoll notification when an incoming transaction arrives. Link: https://lore.kernel.org/rust-for-linux/20231101-rust-binder-v1-7-08ba9197f637@google.com/ Change-Id: I42e874205f4c7901d6914ac014c7e4deadaa2b88 Co-developed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Bug: 278052745
This commit is contained in:
parent
bb1d504151
commit
98cf4f1b76
|
@ -125,8 +125,27 @@ impl ProcessInner {
|
||||||
} else if self.is_dead {
|
} else if self.is_dead {
|
||||||
Err((BinderError::new_dead(), work))
|
Err((BinderError::new_dead(), work))
|
||||||
} else {
|
} else {
|
||||||
// There are no ready threads. Push work to process queue.
|
let sync = work.should_sync_wakeup();
|
||||||
|
|
||||||
|
// Didn't find a thread waiting for proc work; this can happen
|
||||||
|
// in two scenarios:
|
||||||
|
// 1. All threads are busy handling transactions
|
||||||
|
// In that case, one of those threads should call back into
|
||||||
|
// the kernel driver soon and pick up this work.
|
||||||
|
// 2. Threads are using the (e)poll interface, in which case
|
||||||
|
// they may be blocked on the waitqueue without having been
|
||||||
|
// added to waiting_threads. For this case, we just iterate
|
||||||
|
// over all threads not handling transaction work, and
|
||||||
|
// wake them all up. We wake all because we don't know whether
|
||||||
|
// a thread that called into (e)poll is handling non-binder
|
||||||
|
// work currently.
|
||||||
self.work.push_back(work);
|
self.work.push_back(work);
|
||||||
|
|
||||||
|
// Wake up polling threads, if any.
|
||||||
|
for thread in self.threads.values() {
|
||||||
|
thread.notify_if_poll_ready(sync);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1000,11 +1019,16 @@ impl Process {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn poll(
|
pub(crate) fn poll(
|
||||||
_this: ArcBorrow<'_, Process>,
|
this: ArcBorrow<'_, Process>,
|
||||||
_file: &File,
|
file: &File,
|
||||||
_table: &mut PollTable,
|
table: &mut PollTable,
|
||||||
) -> Result<u32> {
|
) -> Result<u32> {
|
||||||
Err(EINVAL)
|
let thread = this.get_current_thread()?;
|
||||||
|
let (from_proc, mut mask) = thread.poll(file, table);
|
||||||
|
if mask == 0 && from_proc && !this.inner.lock().work.is_empty() {
|
||||||
|
mask |= bindings::POLLIN;
|
||||||
|
}
|
||||||
|
Ok(mask)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,13 +9,15 @@
|
||||||
|
|
||||||
use kernel::{
|
use kernel::{
|
||||||
bindings,
|
bindings,
|
||||||
|
file::File,
|
||||||
list::{
|
list::{
|
||||||
AtomicListArcTracker, HasListLinks, List, ListArc, ListArcSafe, ListItem, ListLinks,
|
AtomicListArcTracker, HasListLinks, List, ListArc, ListArcSafe, ListItem, ListLinks,
|
||||||
TryNewListArc,
|
TryNewListArc,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
security,
|
security,
|
||||||
sync::{Arc, CondVar, SpinLock},
|
sync::poll::{PollCondVar, PollTable},
|
||||||
|
sync::{Arc, SpinLock},
|
||||||
types::Either,
|
types::Either,
|
||||||
uaccess::{UserSlice, UserSliceWriter},
|
uaccess::{UserSlice, UserSliceWriter},
|
||||||
};
|
};
|
||||||
|
@ -76,6 +78,7 @@ const LOOPER_EXITED: u32 = 0x04;
|
||||||
const LOOPER_INVALID: u32 = 0x08;
|
const LOOPER_INVALID: u32 = 0x08;
|
||||||
const LOOPER_WAITING: u32 = 0x10;
|
const LOOPER_WAITING: u32 = 0x10;
|
||||||
const LOOPER_WAITING_PROC: u32 = 0x20;
|
const LOOPER_WAITING_PROC: u32 = 0x20;
|
||||||
|
const LOOPER_POLL: u32 = 0x40;
|
||||||
|
|
||||||
impl InnerThread {
|
impl InnerThread {
|
||||||
fn new() -> Result<Self> {
|
fn new() -> Result<Self> {
|
||||||
|
@ -162,6 +165,15 @@ impl InnerThread {
|
||||||
fn should_use_process_work_queue(&self) -> bool {
|
fn should_use_process_work_queue(&self) -> bool {
|
||||||
!self.process_work_list && self.is_looper()
|
!self.process_work_list && self.is_looper()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn poll(&mut self) -> u32 {
|
||||||
|
self.looper_flags |= LOOPER_POLL;
|
||||||
|
if self.process_work_list || self.looper_need_return {
|
||||||
|
bindings::POLLIN
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This represents a thread that's used with binder.
|
/// This represents a thread that's used with binder.
|
||||||
|
@ -172,7 +184,7 @@ pub(crate) struct Thread {
|
||||||
#[pin]
|
#[pin]
|
||||||
inner: SpinLock<InnerThread>,
|
inner: SpinLock<InnerThread>,
|
||||||
#[pin]
|
#[pin]
|
||||||
work_condvar: CondVar,
|
work_condvar: PollCondVar,
|
||||||
/// Used to insert this thread into the process' `ready_threads` list.
|
/// Used to insert this thread into the process' `ready_threads` list.
|
||||||
///
|
///
|
||||||
/// INVARIANT: May never be used for any other list than the `self.process.ready_threads`.
|
/// INVARIANT: May never be used for any other list than the `self.process.ready_threads`.
|
||||||
|
@ -204,7 +216,7 @@ impl Thread {
|
||||||
id,
|
id,
|
||||||
process,
|
process,
|
||||||
inner <- kernel::new_spinlock!(inner, "Thread::inner"),
|
inner <- kernel::new_spinlock!(inner, "Thread::inner"),
|
||||||
work_condvar <- kernel::new_condvar!("Thread::work_condvar"),
|
work_condvar <- kernel::new_poll_condvar!("Thread::work_condvar"),
|
||||||
links <- ListLinks::new(),
|
links <- ListLinks::new(),
|
||||||
links_track <- AtomicListArcTracker::new(),
|
links_track <- AtomicListArcTracker::new(),
|
||||||
}))
|
}))
|
||||||
|
@ -623,6 +635,12 @@ impl Thread {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn poll(&self, file: &File, table: &mut PollTable) -> (bool, u32) {
|
||||||
|
table.register_wait(file, &self.work_condvar);
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
(inner.should_use_process_work_queue(), inner.poll())
|
||||||
|
}
|
||||||
|
|
||||||
/// Make the call to `get_work` or `get_work_local` return immediately, if any.
|
/// Make the call to `get_work` or `get_work_local` return immediately, if any.
|
||||||
pub(crate) fn exit_looper(&self) {
|
pub(crate) fn exit_looper(&self) {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
|
@ -637,6 +655,22 @@ impl Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn notify_if_poll_ready(&self, sync: bool) {
|
||||||
|
// Determine if we need to notify. This requires the lock.
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
let notify = inner.looper_flags & LOOPER_POLL != 0 && inner.should_use_process_work_queue();
|
||||||
|
drop(inner);
|
||||||
|
|
||||||
|
// Now that the lock is no longer held, notify the waiters if we have to.
|
||||||
|
if notify {
|
||||||
|
if sync {
|
||||||
|
self.work_condvar.notify_sync();
|
||||||
|
} else {
|
||||||
|
self.work_condvar.notify_one();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn release(self: &Arc<Self>) {
|
pub(crate) fn release(self: &Arc<Self>) {
|
||||||
self.inner.lock().is_dead = true;
|
self.inner.lock().is_dead = true;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user