diff --git a/kernel/libs/aster-bigtcp/src/iface/common.rs b/kernel/libs/aster-bigtcp/src/iface/common.rs index fdd1dc0d8..b92048881 100644 --- a/kernel/libs/aster-bigtcp/src/iface/common.rs +++ b/kernel/libs/aster-bigtcp/src/iface/common.rs @@ -11,7 +11,7 @@ use alloc::{ }; use keyable_arc::KeyableArc; -use ostd::sync::{LocalIrqDisabled, RwLock, SpinLock, SpinLockGuard}; +use ostd::sync::{LocalIrqDisabled, PreemptDisabled, RwLock, SpinLock, SpinLockGuard}; use smoltcp::{ iface::{SocketHandle, SocketSet}, phy::Device, @@ -27,7 +27,7 @@ use crate::{ pub struct IfaceCommon { interface: SpinLock, sockets: SpinLock, LocalIrqDisabled>, - used_ports: RwLock>, + used_ports: SpinLock, PreemptDisabled>, bound_sockets: RwLock>>>, closing_sockets: SpinLock>>, LocalIrqDisabled>, ext: E, @@ -40,7 +40,7 @@ impl IfaceCommon { Self { interface: SpinLock::new(interface), sockets: SpinLock::new(socket_set), - used_ports: RwLock::new(used_ports), + used_ports: SpinLock::new(used_ports), bound_sockets: RwLock::new(BTreeSet::new()), closing_sockets: SpinLock::new(BTreeSet::new()), ext, @@ -69,7 +69,7 @@ impl IfaceCommon { /// Alloc an unused port range from 49152 ~ 65535 (According to smoltcp docs) fn alloc_ephemeral_port(&self) -> Option { - let mut used_ports = self.used_ports.write(); + let mut used_ports = self.used_ports.lock(); for port in IP_LOCAL_PORT_START..=IP_LOCAL_PORT_END { if let Entry::Vacant(e) = used_ports.entry(port) { e.insert(0); @@ -81,7 +81,7 @@ impl IfaceCommon { #[must_use] fn bind_port(&self, port: u16, can_reuse: bool) -> bool { - let mut used_ports = self.used_ports.write(); + let mut used_ports = self.used_ports.lock(); if let Some(used_times) = used_ports.get_mut(&port) { if *used_times == 0 || can_reuse { // FIXME: Check if the previous socket was bound with SO_REUSEADDR. @@ -97,7 +97,7 @@ impl IfaceCommon { /// Release port number so the port can be used again. For reused port, the port may still be in use. pub(crate) fn release_port(&self, port: u16) { - let mut used_ports = self.used_ports.write(); + let mut used_ports = self.used_ports.lock(); if let Some(used_times) = used_ports.remove(&port) { if used_times != 1 { used_ports.insert(port, used_times - 1); diff --git a/kernel/libs/aster-bigtcp/src/socket/bound.rs b/kernel/libs/aster-bigtcp/src/socket/bound.rs index cc7b0c303..8ca0f53e6 100644 --- a/kernel/libs/aster-bigtcp/src/socket/bound.rs +++ b/kernel/libs/aster-bigtcp/src/socket/bound.rs @@ -46,7 +46,7 @@ impl AnyBoundSocket { /// that the old observer will never be called after the setting. Users should be aware of this /// and proactively handle the race conditions if necessary. pub fn set_observer(&self, new_observer: Weak) { - *self.0.observer.write() = new_observer; + *self.0.observer.write_irq_disabled() = new_observer; self.0.on_iface_events(); } @@ -111,8 +111,12 @@ pub(crate) struct AnyBoundSocketInner { impl AnyBoundSocketInner { pub(crate) fn on_iface_events(&self) { - if let Some(observer) = Weak::upgrade(&*self.observer.read()) { - observer.on_events(); + // We never hold the write lock in IRQ handlers, so we don't need to disable IRQs when we + // get the read lock. + let observer = Weak::upgrade(&*self.observer.read()); + + if let Some(inner) = observer { + inner.on_events(); } }