Avoid nested loops

This commit is contained in:
Ruihan Li
2024-09-01 18:54:17 +08:00
committed by Tate, Hongliang Tian
parent 25daab7e78
commit d70ae181b5

View File

@ -212,55 +212,46 @@ impl EpollFile {
} }
fn pop_ready(&self, max_events: usize, ep_events: &mut Vec<EpollEvent>) -> usize { fn pop_ready(&self, max_events: usize, ep_events: &mut Vec<EpollEvent>) -> usize {
let mut count_events = 0;
let mut ready = self.ready.lock(); let mut ready = self.ready.lock();
let mut pop_quota = ready.len();
loop { let mut count_events = 0;
// Pop some ready entries per round. for _ in 0..ready.len() {
// if count_events >= max_events {
// Since the popped ready entries may contain "false positive" and
// we want to return as many results as possible, this has to
// be done in a loop.
let pop_count = (max_events - count_events).min(pop_quota);
if pop_count == 0 {
break; break;
} }
let ready_entries: Vec<Arc<EpollEntry>> = ready
.drain(..pop_count)
.filter_map(|entry| Weak::upgrade(&entry))
.collect();
pop_quota -= pop_count;
// Examine these ready entries, which are candidates for the results let weak_entry = ready.pop_front().unwrap();
// to be returned. let Some(entry) = Weak::upgrade(&weak_entry) else {
for entry in ready_entries { // The entry has been deleted.
let (ep_event, ep_flags) = entry.event_and_flags(); continue;
// If this entry's file is ready, save it in the output array. };
// EPOLLHUP and EPOLLERR should always be reported.
let ready_events = entry.poll() & (ep_event.events | IoEvents::HUP | IoEvents::ERR);
// Records the events from the ready list let (ep_event, ep_flags) = entry.event_and_flags();
if !ready_events.is_empty() { // If this entry's file is ready, save it in the output array.
ep_events.push(EpollEvent::new(ready_events, ep_event.user_data)); // EPOLLHUP and EPOLLERR should always be reported.
count_events += 1; let ready_events = entry.poll() & (ep_event.events | IoEvents::HUP | IoEvents::ERR);
}
// If there are events and the epoll entry is neither edge-triggered // Records the events from the ready list
// nor one-shot, then we should keep the entry in the ready list. if !ready_events.is_empty() {
if !ready_events.is_empty() ep_events.push(EpollEvent::new(ready_events, ep_event.user_data));
&& !ep_flags.intersects(EpollFlags::ONE_SHOT | EpollFlags::EDGE_TRIGGER) count_events += 1;
{ }
ready.push_back(Arc::downgrade(&entry));
} // If there are events and the epoll entry is neither edge-triggered
// Otherwise, the entry is indeed removed the ready list and we should reset // nor one-shot, then we should keep the entry in the ready list.
// its ready flag. if !ready_events.is_empty()
else { && !ep_flags.intersects(EpollFlags::ONE_SHOT | EpollFlags::EDGE_TRIGGER)
entry.reset_ready(); {
// For EPOLLONESHOT flag, this entry should also be removed from the interest list ready.push_back(weak_entry);
if ep_flags.intersects(EpollFlags::ONE_SHOT) { }
self.del_interest(entry.fd()) // Otherwise, the entry is indeed removed the ready list and we should reset
.expect("this entry should be in the interest list"); // its ready flag.
} else {
entry.reset_ready();
// For EPOLLONESHOT flag, this entry should also be removed from the interest list
if ep_flags.intersects(EpollFlags::ONE_SHOT) {
self.del_interest(entry.fd())
.expect("this entry should be in the interest list");
} }
} }
} }
@ -269,6 +260,7 @@ impl EpollFile {
if ready.len() == 0 { if ready.len() == 0 {
self.pollee.del_events(IoEvents::IN); self.pollee.del_events(IoEvents::IN);
} }
count_events count_events
} }