Rewrite the Poller&Pollee with Observer&Subject

This commit is contained in:
LI Qing
2023-04-24 16:47:40 +08:00
committed by Tate, Hongliang Tian
parent 2b1ecdcfa6
commit aec46295c4
11 changed files with 155 additions and 116 deletions

View File

@ -76,7 +76,7 @@ impl EpollFile {
if interest.contains_key(&fd) {
return_errno_with_message!(Errno::EEXIST, "the fd has been added");
}
file.register_observer(entry.clone(), IoEvents::all())?;
file.register_observer(entry.self_weak() as _, IoEvents::all())?;
interest.insert(fd, entry.clone());
// Register self to the file table entry
file_table_entry.register_observer(self.weak_self.clone() as _);
@ -113,7 +113,7 @@ impl EpollFile {
None => return Ok(()),
};
file.unregister_observer(&(entry as _)).unwrap();
file.unregister_observer(&(entry.self_weak() as _)).unwrap();
Ok(())
}
@ -294,7 +294,7 @@ impl Drop for EpollFile {
.map(|(fd, entry)| {
entry.set_deleted();
if let Some(file) = entry.file() {
let _ = file.unregister_observer(&(entry as _));
let _ = file.unregister_observer(&(entry.self_weak() as _));
}
fd
})
@ -326,7 +326,7 @@ impl FileLike for EpollFile {
fn register_observer(
&self,
observer: Arc<dyn Observer<IoEvents>>,
observer: Weak<dyn Observer<IoEvents>>,
mask: IoEvents,
) -> Result<()> {
self.pollee.register_observer(observer, mask);
@ -335,8 +335,8 @@ impl FileLike for EpollFile {
fn unregister_observer(
&self,
observer: &Arc<dyn Observer<IoEvents>>,
) -> Result<Arc<dyn Observer<IoEvents>>> {
observer: &Weak<dyn Observer<IoEvents>>,
) -> Result<Weak<dyn Observer<IoEvents>>> {
self.pollee
.unregister_observer(observer)
.ok_or_else(|| Error::with_message(Errno::ENOENT, "observer is not registered"))
@ -398,6 +398,11 @@ impl EpollEntry {
self.weak_self.upgrade().unwrap()
}
/// Get an instance of `Weak` that refers to this epoll entry.
pub fn self_weak(&self) -> Weak<Self> {
self.weak_self.clone()
}
/// Get the file associated with this epoll entry.
///
/// Since an epoll entry only holds a weak reference to the file,

View File

@ -51,7 +51,7 @@ pub trait FileLike: Send + Sync + Any {
fn register_observer(
&self,
observer: Arc<dyn Observer<IoEvents>>,
observer: Weak<dyn Observer<IoEvents>>,
mask: IoEvents,
) -> Result<()> {
return_errno_with_message!(Errno::EINVAL, "register_observer is not supported")
@ -59,8 +59,8 @@ pub trait FileLike: Send + Sync + Any {
fn unregister_observer(
&self,
observer: &Arc<dyn Observer<IoEvents>>,
) -> Result<Arc<dyn Observer<IoEvents>>> {
observer: &Weak<dyn Observer<IoEvents>>,
) -> Result<Weak<dyn Observer<IoEvents>>> {
return_errno_with_message!(Errno::EINVAL, "unregister_observer is not supported")
}

View File

@ -114,7 +114,7 @@ impl FileTable {
}
pub fn register_observer(&self, observer: Weak<dyn Observer<FdEvents>>) {
self.subject.register_observer(observer);
self.subject.register_observer(observer, ());
}
pub fn unregister_observer(&self, observer: &Weak<dyn Observer<FdEvents>>) {
@ -170,7 +170,7 @@ impl FileTableEntry {
}
pub fn register_observer(&self, epoll: Weak<dyn Observer<FdEvents>>) {
self.subject.register_observer(epoll);
self.subject.register_observer(epoll, ());
}
pub fn unregister_observer(&self, epoll: &Weak<dyn Observer<FdEvents>>) {

View File

@ -45,7 +45,7 @@ impl FileLike for PipeReader {
fn register_observer(
&self,
observer: Arc<dyn Observer<IoEvents>>,
observer: Weak<dyn Observer<IoEvents>>,
mask: IoEvents,
) -> Result<()> {
self.consumer.register_observer(observer, mask)
@ -53,8 +53,8 @@ impl FileLike for PipeReader {
fn unregister_observer(
&self,
observer: &Arc<dyn Observer<IoEvents>>,
) -> Result<Arc<dyn Observer<IoEvents>>> {
observer: &Weak<dyn Observer<IoEvents>>,
) -> Result<Weak<dyn Observer<IoEvents>>> {
self.consumer.unregister_observer(observer)
}
@ -104,7 +104,7 @@ impl FileLike for PipeWriter {
fn register_observer(
&self,
observer: Arc<dyn Observer<IoEvents>>,
observer: Weak<dyn Observer<IoEvents>>,
mask: IoEvents,
) -> Result<()> {
self.producer.register_observer(observer, mask)
@ -112,8 +112,8 @@ impl FileLike for PipeWriter {
fn unregister_observer(
&self,
observer: &Arc<dyn Observer<IoEvents>>,
) -> Result<Arc<dyn Observer<IoEvents>>> {
observer: &Weak<dyn Observer<IoEvents>>,
) -> Result<Weak<dyn Observer<IoEvents>>> {
self.producer.unregister_observer(observer)
}

View File

@ -83,7 +83,7 @@ macro_rules! impl_common_methods_for_channel {
pub fn register_observer(
&self,
observer: Arc<dyn Observer<IoEvents>>,
observer: Weak<dyn Observer<IoEvents>>,
mask: IoEvents,
) -> Result<()> {
self.this_end().pollee.register_observer(observer, mask);
@ -92,8 +92,8 @@ macro_rules! impl_common_methods_for_channel {
pub fn unregister_observer(
&self,
observer: &Arc<dyn Observer<IoEvents>>,
) -> Result<Arc<dyn Observer<IoEvents>>> {
observer: &Weak<dyn Observer<IoEvents>>,
) -> Result<Weak<dyn Observer<IoEvents>>> {
self.this_end()
.pollee
.unregister_observer(observer)

View File

@ -1,4 +1,4 @@
use crate::events::Events;
use crate::events::{Events, EventsFilter};
crate::bitflags! {
pub struct IoEvents: u32 {
@ -15,3 +15,9 @@ crate::bitflags! {
}
impl Events for IoEvents {}
impl EventsFilter<IoEvents> for IoEvents {
fn filter(&self, events: &IoEvents) -> bool {
self.intersects(*events)
}
}

View File

@ -1,10 +1,10 @@
use super::IoEvents;
use crate::events::Observer;
use crate::events::{Observer, Subject};
use crate::prelude::*;
use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
use jinux_frame::sync::WaitQueue;
use keyable_arc::KeyableArc;
use keyable_arc::KeyableWeak;
/// A pollee maintains a set of active events, which can be polled with
/// pollers or be monitored with observers.
@ -13,21 +13,18 @@ pub struct Pollee {
}
struct PolleeInner {
// A table that maintains all interesting pollers
pollers: Mutex<BTreeMap<KeyableArc<dyn Observer<IoEvents>>, IoEvents>>,
// For efficient manipulation, we use AtomicU32 instead of RwLock<IoEvents>
// A subject which is monitored with pollers.
subject: Subject<IoEvents, IoEvents>,
// For efficient manipulation, we use AtomicU32 instead of RwLock<IoEvents>.
events: AtomicU32,
// To reduce lock contentions, we maintain a counter for the size of the table
num_pollers: AtomicUsize,
}
impl Pollee {
/// Creates a new instance of pollee.
pub fn new(init_events: IoEvents) -> Self {
let inner = PolleeInner {
pollers: Mutex::new(BTreeMap::new()),
subject: Subject::new(),
events: AtomicU32::new(init_events.bits()),
num_pollers: AtomicUsize::new(0),
};
Self {
inner: Arc::new(inner),
@ -51,7 +48,7 @@ impl Pollee {
return revents;
}
// Slow path: register the provided poller
// Register the provided poller.
self.register_poller(poller.unwrap(), mask);
// It is important to check events again to handle race conditions
@ -60,17 +57,11 @@ impl Pollee {
}
fn register_poller(&self, poller: &Poller, mask: IoEvents) {
let mut pollers = self.inner.pollers.lock();
let is_new = {
let observer = poller.observer();
pollers.insert(observer, mask).is_none()
};
if is_new {
let mut pollees = poller.inner.pollees.lock();
pollees.push(Arc::downgrade(&self.inner));
self.inner.num_pollers.fetch_add(1, Ordering::Release);
}
self.inner
.subject
.register_observer(poller.observer(), mask);
let mut pollees = poller.inner.pollees.lock();
pollees.insert(Arc::downgrade(&self.inner).into(), ());
}
/// Register an IoEvents observer.
@ -84,23 +75,9 @@ impl Pollee {
///
/// Note that the observer will always get notified of the events in
/// `IoEvents::ALWAYS_POLL` regardless of the value of `mask`.
///
/// # Memory leakage
///
/// Since an `Arc` for each observer is kept internally by a pollee,
/// it is important for the user to call the `unregister_observer` method
/// when the observer is no longer interested in the pollee. Otherwise,
/// the observer will not be dropped.
pub fn register_observer(&self, observer: Arc<dyn Observer<IoEvents>>, mask: IoEvents) {
let mut pollers = self.inner.pollers.lock();
let is_new = {
let observer: KeyableArc<dyn Observer<IoEvents>> = observer.into();
let mask = mask | IoEvents::ALWAYS_POLL;
pollers.insert(observer, mask).is_none()
};
if is_new {
self.inner.num_pollers.fetch_add(1, Ordering::Release);
}
pub fn register_observer(&self, observer: Weak<dyn Observer<IoEvents>>, mask: IoEvents) {
let mask = mask | IoEvents::ALWAYS_POLL;
self.inner.subject.register_observer(observer, mask);
}
/// Unregister an IoEvents observer.
@ -110,17 +87,9 @@ impl Pollee {
/// a `None` will be returned.
pub fn unregister_observer(
&self,
observer: &Arc<dyn Observer<IoEvents>>,
) -> Option<Arc<dyn Observer<IoEvents>>> {
let observer: KeyableArc<dyn Observer<IoEvents>> = observer.clone().into();
let mut pollers = self.inner.pollers.lock();
let observer = pollers
.remove_entry(&observer)
.map(|(observer, _)| observer.into());
if observer.is_some() {
self.inner.num_pollers.fetch_sub(1, Ordering::Relaxed);
}
observer
observer: &Weak<dyn Observer<IoEvents>>,
) -> Option<Weak<dyn Observer<IoEvents>>> {
self.inner.subject.unregister_observer(observer)
}
/// Add some events to the pollee's state.
@ -129,18 +98,7 @@ impl Pollee {
/// the added events.
pub fn add_events(&self, events: IoEvents) {
self.inner.events.fetch_or(events.bits(), Ordering::Release);
// Fast path
if self.inner.num_pollers.load(Ordering::Relaxed) == 0 {
return;
}
// Slow path: broadcast the new events to all pollers
let pollers = self.inner.pollers.lock();
pollers
.iter()
.filter(|(_, mask)| mask.intersects(events))
.for_each(|(poller, mask)| poller.on_events(&(events & *mask)));
self.inner.subject.notify_observers(&events);
}
/// Remove some events from the pollee's state.
@ -170,14 +128,14 @@ impl Pollee {
/// A poller gets notified when its associated pollees have interesting events.
pub struct Poller {
inner: KeyableArc<PollerInner>,
inner: Arc<PollerInner>,
}
struct PollerInner {
// Use event counter to wait or wake up a poller
event_counter: EventCounter,
// All pollees that are interesting to this poller
pollees: Mutex<Vec<Weak<PolleeInner>>>,
pollees: Mutex<BTreeMap<KeyableWeak<PolleeInner>, ()>>,
}
impl Poller {
@ -185,10 +143,10 @@ impl Poller {
pub fn new() -> Self {
let inner = PollerInner {
event_counter: EventCounter::new(),
pollees: Mutex::new(Vec::with_capacity(1)),
pollees: Mutex::new(BTreeMap::new()),
};
Self {
inner: KeyableArc::new(inner),
inner: Arc::new(inner),
}
}
@ -197,8 +155,8 @@ impl Poller {
self.inner.event_counter.read();
}
fn observer(&self) -> KeyableArc<dyn Observer<IoEvents>> {
self.inner.clone() as KeyableArc<dyn Observer<IoEvents>>
fn observer(&self) -> Weak<dyn Observer<IoEvents>> {
Arc::downgrade(&self.inner) as _
}
}
@ -216,14 +174,9 @@ impl Drop for Poller {
}
let self_observer = self.observer();
for weak_pollee in pollees.drain(..) {
for (weak_pollee, _) in pollees.drain_filter(|_, _| true) {
if let Some(pollee) = weak_pollee.upgrade() {
let mut pollers = pollee.pollers.lock();
let res = pollers.remove(&self_observer);
assert!(res.is_some());
drop(pollers);
pollee.num_pollers.fetch_sub(1, Ordering::Relaxed);
pollee.subject.unregister_observer(&self_observer);
}
}
}