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 {
|
||||
Err((BinderError::new_dead(), work))
|
||||
} 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);
|
||||
|
||||
// Wake up polling threads, if any.
|
||||
for thread in self.threads.values() {
|
||||
thread.notify_if_poll_ready(sync);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1000,11 +1019,16 @@ impl Process {
|
|||
}
|
||||
|
||||
pub(crate) fn poll(
|
||||
_this: ArcBorrow<'_, Process>,
|
||||
_file: &File,
|
||||
_table: &mut PollTable,
|
||||
this: ArcBorrow<'_, Process>,
|
||||
file: &File,
|
||||
table: &mut PollTable,
|
||||
) -> 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::{
|
||||
bindings,
|
||||
file::File,
|
||||
list::{
|
||||
AtomicListArcTracker, HasListLinks, List, ListArc, ListArcSafe, ListItem, ListLinks,
|
||||
TryNewListArc,
|
||||
},
|
||||
prelude::*,
|
||||
security,
|
||||
sync::{Arc, CondVar, SpinLock},
|
||||
sync::poll::{PollCondVar, PollTable},
|
||||
sync::{Arc, SpinLock},
|
||||
types::Either,
|
||||
uaccess::{UserSlice, UserSliceWriter},
|
||||
};
|
||||
|
@ -76,6 +78,7 @@ const LOOPER_EXITED: u32 = 0x04;
|
|||
const LOOPER_INVALID: u32 = 0x08;
|
||||
const LOOPER_WAITING: u32 = 0x10;
|
||||
const LOOPER_WAITING_PROC: u32 = 0x20;
|
||||
const LOOPER_POLL: u32 = 0x40;
|
||||
|
||||
impl InnerThread {
|
||||
fn new() -> Result<Self> {
|
||||
|
@ -162,6 +165,15 @@ impl InnerThread {
|
|||
fn should_use_process_work_queue(&self) -> bool {
|
||||
!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.
|
||||
|
@ -172,7 +184,7 @@ pub(crate) struct Thread {
|
|||
#[pin]
|
||||
inner: SpinLock<InnerThread>,
|
||||
#[pin]
|
||||
work_condvar: CondVar,
|
||||
work_condvar: PollCondVar,
|
||||
/// 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`.
|
||||
|
@ -204,7 +216,7 @@ impl Thread {
|
|||
id,
|
||||
process,
|
||||
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_track <- AtomicListArcTracker::new(),
|
||||
}))
|
||||
|
@ -623,6 +635,12 @@ impl Thread {
|
|||
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.
|
||||
pub(crate) fn exit_looper(&self) {
|
||||
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>) {
|
||||
self.inner.lock().is_dead = true;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user