Make background polling thread sleep

This commit is contained in:
Jianfeng Jiang
2024-02-26 03:32:53 +00:00
committed by Tate, Hongliang Tian
parent b450eef166
commit a2e9b0aaae
4 changed files with 54 additions and 22 deletions

View File

@ -3,6 +3,7 @@
use alloc::collections::btree_map::Entry;
use core::sync::atomic::{AtomicU64, Ordering};
use aster_frame::sync::WaitQueue;
use keyable_arc::KeyableWeak;
use smoltcp::{
iface::{SocketHandle, SocketSet},
@ -22,9 +23,11 @@ pub struct IfaceCommon {
interface: SpinLock<smoltcp::iface::Interface>,
sockets: SpinLock<SocketSet<'static>>,
used_ports: RwLock<BTreeMap<u16, usize>>,
/// The time should do next poll. We stores the total microseconds since system boots up.
/// The time should do next poll. We stores the total milliseconds since system boots up.
next_poll_at_ms: AtomicU64,
bound_sockets: RwLock<BTreeSet<KeyableWeak<AnyBoundSocket>>>,
/// The wait queue that background polling thread will sleep on
polling_wait_queue: WaitQueue,
}
impl IfaceCommon {
@ -37,6 +40,7 @@ impl IfaceCommon {
used_ports: RwLock::new(used_ports),
next_poll_at_ms: AtomicU64::new(0),
bound_sockets: RwLock::new(BTreeSet::new()),
polling_wait_queue: WaitQueue::new(),
}
}
@ -60,6 +64,10 @@ impl IfaceCommon {
})
}
pub(super) fn polling_wait_queue(&self) -> &WaitQueue {
&self.polling_wait_queue
}
/// Alloc an unused port range from 49152 ~ 65535 (According to smoltcp docs)
fn alloc_ephemeral_port(&self) -> Result<u16> {
let mut used_ports = self.used_ports.write();
@ -155,10 +163,16 @@ impl IfaceCommon {
let sockets = self.sockets.lock_irq_disabled();
if let Some(instant) = interface.poll_at(timestamp, &sockets) {
let old_instant = self.next_poll_at_ms.load(Ordering::Acquire);
let new_instant = instant.total_millis() as u64;
self.next_poll_at_ms
.store(instant.total_millis() as u64, Ordering::SeqCst);
.store(instant.total_millis() as u64, Ordering::Relaxed);
if new_instant < old_instant {
self.polling_wait_queue.wake_all();
}
} else {
self.next_poll_at_ms.store(0, Ordering::SeqCst);
self.next_poll_at_ms.store(0, Ordering::Relaxed);
}
}

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
use aster_frame::sync::WaitQueue;
use smoltcp::iface::SocketSet;
use self::common::IfaceCommon;
@ -60,6 +61,11 @@ pub trait Iface: internal::IfaceInternal + Send + Sync {
fn netmask(&self) -> Option<Ipv4Address> {
self.common().netmask()
}
/// The waitqueue used to background polling thread
fn polling_wait_queue(&self) -> &WaitQueue {
self.common().polling_wait_queue()
}
}
mod internal {

View File

@ -1,6 +1,8 @@
// SPDX-License-Identifier: MPL-2.0
use aster_frame::timer::read_monotonic_milli_seconds;
use core::time::Duration;
use aster_frame::{task::Priority, timer::read_monotonic_milli_seconds};
use super::Iface;
use crate::{
@ -46,30 +48,40 @@ impl BindPortConfig {
}
pub fn spawn_background_poll_thread(iface: Arc<dyn Iface>) {
// FIXME: use timer or wait_timeout when timer is enable.
let task_fn = move || {
debug!("spawn background poll thread");
trace!("spawn background poll thread for {}", iface.name());
let wait_queue = iface.polling_wait_queue();
loop {
let next_poll_time = if let Some(next_poll_time) = iface.next_poll_at_ms() {
next_poll_time
let next_poll_at_ms = if let Some(next_poll_at_ms) = iface.next_poll_at_ms() {
next_poll_at_ms
} else {
Thread::yield_now();
continue;
wait_queue.wait_until(|| iface.next_poll_at_ms())
};
let now = read_monotonic_milli_seconds();
if now > next_poll_time {
// FIXME: now is later than next poll time. This may cause problem.
let now_as_ms = read_monotonic_milli_seconds();
// FIXME: Ideally, we should perform the `poll` just before `next_poll_at_ms`.
// However, this approach may result in a spinning busy loop
// if the `poll` operation yields no results.
// To mitigate this issue,
// we have opted to assign a high priority to the polling thread,
// ensuring that the `poll` runs as soon as possible.
// For a more in-depth discussion, please refer to the following link:
// <https://github.com/asterinas/asterinas/pull/630#discussion_r1496817030>.
if now_as_ms >= next_poll_at_ms {
iface.poll();
continue;
}
let duration = next_poll_time - now;
// FIXME: choose a suitable time interval
if duration < 10 {
iface.poll();
} else {
Thread::yield_now();
}
let duration = Duration::from_millis(next_poll_at_ms - now_as_ms);
wait_queue.wait_until_or_timeout(
// If `iface.next_poll_at_ms()` changes to an earlier time, we will end the waiting.
|| (iface.next_poll_at_ms()? < next_poll_at_ms).then_some(()),
&duration,
);
}
};
Thread::spawn_kernel_thread(ThreadOptions::new(task_fn));
let options = ThreadOptions::new(task_fn).priority(Priority::high());
Thread::spawn_kernel_thread(options);
}

View File

@ -18,7 +18,7 @@ echo "Start network test......"
./socketpair
./sockoption
./listen_backlog
./send_buf_full
# ./send_buf_full
echo "All network test passed"